print compiler macro definitions

Compilers define macros that can be used to identify a compiler and platform from within C, C++ and Fortran code. This can be useful for many purposes where short bits of platform-specific or compiler-specific code is needed. If a significant amount of code is needed, it may be better to swap in different code files using the build system instead of lengthly #if defined(foo) logic. There are numerous examples for C and C++ so here we will focus on macros of Fortran compilers.


Gfortran compiler macro definitions are obtained in an OS-agnostic way by:

echo "" | gfortran -dM -E - > macros.txt

that creates a file “macros.txt” containing all the compiler macros.

commonly used macros to detect operating system / compiler configuration include:

  • _WIN32 1
  • __linux__ 1
  • __unix__ 1
  • __APPLE__ 1

Intel Fortran

Intel Fortran compiler macros include the Gfortran macros noted above and additionally:


PGI Fortran

PGI Fortran compiler macros are printed by:

pgfortran -dM

the PGI macros include the Gfortran macros above as well as:

  • __PGI 1


Flang macros include

  • __FLANG 1

Other compilers

Other Fortran compiler macros that identify the compiler and platform can be found in CMake source code.

CMake FetchContent vs. ExternalProject

Making multiple software projects work together is usually better done by the build system:

instead of Git submodule.

Meson subproject and CMake ExternalProject keep project namespaces separate. Meson subproject and CMake FetchContent download and configure all projects at configure time. CMake FetchContent comingles the CMake project namespaces. FetchContent can be easier to use than ExternalProject if you control both software projects’ CMake scripts. If you don’t control the “child” project, it may be better to use ExternalProject instead of FetchContent.

For these examples, suppose we have a top-level project “parent” and a “child” project containing a library that is desired in parent. Suppose the child project can be built standalone (by itself) but also may be used directly from other CMake projects.

child: standalone~/bar~/bar/build~/bar
child: CMake ExternalProject~/foo/build/child-prefix/src/child~/foo/build/child-prefix/src/child-build~/foo/build/child-prefix/src/child
child: CMake FetchContent~/foo~/foo/build~/foo/build/_deps/child-src


FetchContent populates content from the other project at configure time. FetchContent populates the “child” project with default values from the “parent” project. Varibles set in the “child” project generally do not affect the “parent” project unless specifically used from the “parent” project.

From “parent” project CMakeLists.txt:

cmake_minimum_required(VERSION 3.14)
project(parent Fortran)

  GIT_REPOSITORY https://github.invalid/username/child.git
  GIT_TAG master   # it's much better to use a specific Git revision or Git tag for reproducibility


# your program
add_executable(myprog main.f90)
target_link_libraries(myprog mylib)  # mylib is from "child"
make “child” code configure, populating variables and targets as if it were part of “parent” CMake project.

suppose “child” project CMakeLists.txt contains:

project(child Fortran)

add_library(mylib mylib.f90)
target_include_libraries(mylib INTERFACE ${CMAKE_CURRENT_BINARY_DIR}/include)
set_target_properties(mylib PROPERTIES

The child project CMAKE_BINARY_DIR and CMAKE_SOURCE_DIR will be those of parent project. That is, if the parent project is in ~/foo and the build directory is ~/foo/build, then the child project in ~/childcode called by FetchContent will also have CMAKE_SOURCE_DIR of ~/foo and CMAKE_BINARY_DIR of ~/foo/build. So be careful in the child project when using such variables that may be defined by parent projects. This is why projects that aren’t specifically designed to work together may be better joined by ExternalProject. A typical technique within the child project that can operate standalone is to refer to CMAKE_CURRENT_SOURCE_DIR instead of CMAKE_SOURCE_DIR as the latter will break when used from FetchContent.


ExternalProject populates content from the other project at build time. This means the other project’s libraries are not visible until the parent project is built. Since ExternalProject does not combine the project namespaces, ExternalProject may be necessary if you don’t control the other projects.

ExternalProject will not download, configure or build without the add_dependencies() statement. Upon cmake --build of the parent project, ExternalProject downloads, configures and builds.

From “parent” project CMakeLists.txt:

project(parent Fortran)


  GIT_TAG master  # it's much better to use a specific Git revision or Git tag for reproducability
  INSTALL_COMMAND ""  # this disables the install step for the external project

ExternalProject_Get_Property(child_proj BINARY_DIR)

file(MAKE_DIRECTORY ${BINARY_DIR}/include)  # avoid race condition

add_library(timestwo STATIC IMPORTED GLOBAL)
set_target_properties(timestwo PROPERTIES

add_executable(test_timestwo test_timestwo.f90)  # your program
add_dependencies(test_timestwo child_proj)  # externalproject won't download without this
target_link_libraries(test_timestwo timestwo)
make ExternalProject always update and build first

The imported library ext is used in the “parent” project just like any other library.

“child” project CMakeLists.txt includes:

project(child Fortran)

add_library(timestwo STATIC timestwo.f90)
set_target_properties(timestwo PROPERTIES

Configure “child” Fortran_MODULE_DIRECTORY so that it’s not necessary for “parent” to introspect “child” directory structure.

Live examples


Since the ExternalProject is built by itself and generally is unaware of the consuming “parent”, this does NOT work to detect use as an ExternalProject:

project(child ...)

# "is_fetched" is:
# * ExternalProject: false--does not detect
# * FetchContent: true


Note that the PARENT_DIRECTORY property is NOT useful for detecting if the “child” is being used as an ExternalProject.

  • target_link_directories() is generally NOT preferred because library name collisions can occur, particularly with system libraries.

List all CMake tests with CTest

As a CMake project grows, the increasing complexity can make it hard to remember what tests are to be run. Perhaps the project logic is unexpectedly omitting necessary tests. The CI system or human can verify the list of tests is as expected by parsing the simple text output from:

ctest -N

before this, the project must be configured and built as usual:

cmake -B build
cmake --build build --parallel
cd build
ctest -N

Git commit date / time / author edit

If the Git commits have already been push to remote, this process will require other users of the repo to reset or reclone. That’s true with any Git operation that edits history. If the Git commits have not already been pushed, then this process will not require extra steps from other repo users.

show commit AuthorDate CommitDate

In general, show any commit’s AuthorDate and CommitDate by

git show <commit_hash> --pretty=fuller

for the most recent commit, simply:

git show --pretty=fuller

edit last commit only

To reset the author of the last commit to the current Git username and email, as well as setting AuthorDate and CommitDate to the current time:

git commit --amend --reset-author --no-edit
reset date/time/author to current
skip opening text editor

edit previous commits, including already pushed

Use git rebase -i as usual and for the commits to reset author / date, change the operation to e to edit each by:

git commit --amend --reset-author --no-edit


GitHub commit troubleshooting

HDF5 on Intel Fortran for Windows

Intel Fortran on Windows provides an easy way to use Fortran MPI on Windows. The Intel Fortran compile and link commands on Windows are distinct from those on Linux / MacOS, perhaps reflecting the internal use of Visual Studio on Windows. The HDF5 1.10.6 release changed the naming convention for the HDF5 Fortran library files on all operating systems.

  • old: hdf5hl_fortran.
  • new: hdf5_hl_fortran.

CMake’s FindHDF5.cmake did not have this change in CMake 3.16.2. We created a CMake Issue for this.

Tentatively one can compile using HDF5 with Intel Fortran on Windows like:

ifort -I"C:/Program Files/HDF_Group/HDF5/1.10.6/include/shared" -I"C:/Program Files/HDF_Group/HDF5/1.10.6/include/static" test_minimal.f90 "C:/Program Files/HDF_Group/HDF5/1.10.6/lib/hdf5_fortran.lib" "C:/Program Files/HDF_Group/HDF5/1.10.6/lib/hdf5_hl_fortran.lib" "C:/Program Files/HDF_Group/HDF5/1.10.6/lib/hdf5.lib" "C:/Program Files/HDF_Group/HDF5/1.10.6/lib/szip.lib" "C:/Program Files/HDF_Group/HDF5/1.10.6/lib/zlib.lib"

If you use include/static you will get errors like

error LNK2019: unresolved external symbol H5GLOBAL_mp_H5F_ACC_TRUNC_F referenced in function MAIN__

ConnectBot cannot import OpenSSH keys

The free open source SSH app ConnectBot allows connecting to SSH servers with port forwarding using public key authentication, including ED25519.


Sometimes it’s necessary to share SSH keypairs on multiple clients. Perhaps the server owner isn’t willing to bother with more than one SSH client key, and you don’t have shell access on SSH login to add another key yourself. ConnectBot has an open issue since it cannot import OpenSSH keys created on a PC.

Generally users should create unique SSH public/private keypairs for each device. Sharing keys between devices means if a device is compromised, deleting its key from ~/.ssh/authorized_keys on the SSH server disables all other devices sharing that key.


Create an SSH keypair in ConnectBot. Copy the ConnectBot-created public/private keypair to the PC ~/.ssh directory.

The stem (filename without extension) of the public and private keys must match. The public key should have a .pub suffix, while the private key has no suffix.

Thereby the same SSH keypair is used on your phone with ConnectBot and your PC with OpenSSH client.

USA 2G cellular shutdown

Carriers in numerous countries worldwide have shutdown 2G networks to free spectrum for 3G, 4G and 5G services. Embedded modems such as automotive (OnStar) and alarm systems may again be impacted by these shutdowns. In developing regions we anticipate 2G networks will linger for several more years, due to cost-effective legacy devices.

Those designing IoT and other embedded devices with cellular modems should consider LPWA 4G LTE, particularly Cat M1 and NB1 to help ensure global functionality. Each geopolitical region has unique LTE bands, but often OEM modules with the same pinout have region-specific models. OEM LTE modules will incorporate at least some bands for each region, so that global LTE roaming for even inexpensive LTE modems will become increasingly common.


The USA 1G AMPS and 2G D-AMPS networks were shutdown in 2008. In June 2013, Sprint shutdown the Nextel iDEN network for LTE band 26.

Recovering from broken Git repo

A local Git repo can become corrupted in rare circumstances, perhaps doing a git commit just as a computer crashes or loses power. A common symptom of a corrupted local Git repo is any Git command except for perhaps git diff giving error:

fatal: your current branch appears to be broken

The changes are likely still present, as seen via git diff. Previous commits that were not pushed to remote are likely present as well in the form of the modified files, but the historical local Git commit deltas may not be recoverable. This recovery will in effect “squash” the local commits that weren’t previously pushed to remote.

NOTE: work done on other branches that weren’t pushed to remote may not be retrievable.


  1. Copy the directory tree of the affected local Git repo, preferably on another hard drive or in the cloud.
  2. git clone a fresh copy of the remote Git repo to a new directory
  3. use a program like Meld to incrementally copy into the new directory the changes from the old corrupted directory. If there are a large number of changes, consider making the changes via multiple Git commits.


DraftSight no longer available on Linux

On Jan 2, 2020 DraftSight Linux discontinuation was announced. Consider libre free CAD programs that work on Linux, MacOS and Windows instead of DraftSight. DraftSight is a non-free program available for Windows only, and in the future for cloud.

3DS DraftSight has 2-D and some 3-D functionality. All no-cost DraftSight licenses were terminated on 31 DEC 2019.

DraftSight was provided at no cost from 2010-2019 for Windows, MacOS and Linux. DraftSight is natively compatible with AutoCAD DWG / DXF formats through R2018 (used by AutoCAD 2020).


If you have a high resolution screen and the DraftSight GUI icons look too small, try Tools → Options → System Options → Display → Screen Options → Use Large Icons.

Free Libre 2-D CAD overview

This article is for AutoCAD 2-D libre alternatives available for Linux, MacOS and Windows. Other free CAD programs exist, but they generally require retraining for users coming from AutoCAD.

Libre 2-D AutoCAD-like

Libre 2-D AutoCAD-like choices include:

  • QCAD
  • LibreCAD

DWG for QCAD and LibreCAD is via the free ODA DWG ↔ DXF converter. FreeCAD is 3-D parametric modeling akin to SolidWorks. FreeCAD can import DXF or DWG using ODA DWG ↔ DXF converter.

2-D CAD comparison

DWGODA R2020read: libdxfrw R2017. write: ODA R2020


QCAD has distinct paid vs. Community Edition features

  • DXF: native read/write
  • DWG: non-free (paid) library OR use free ODA DXF-DWG converter.



  • DXF: native read/write
  • DWG read: through R2017 (R2013 format) libdxfrw
  • DWG write: use ODA DXF-DWG converter.


Free, non-libre ODA File Converter supports through R2020 DWG/DXF. ODA File Converter may be used to convert from DXF to DWG en masse as a first/last step. The OpenDesignAlliance is the same organization where QCad gets its non-free non-libre converter.