Scientific Computing

CMake Git inactivity timeout

CMake Git operations such as shallow clone can cause unexpected failures due to too small INACTIVITY_TIMEOUT in ExternalProject or FetchContent. Be sure to set INACTIVITY_TIMEOUT to a large enough value. 15 seconds is too short a timeout for Git shallow clone, for example. Consider 60 seconds or larger INACTIVITY_TIMEOUT.

Check for timeout in:

git config --get http.lowSpeedLimit
git config --get http.lowSpeedTime

lowSpeedLimit might be set to 1000 (bits/second) or as appropriate for the network. If lowSpeedTime is too short, this download failure can also occur. Set to 60 seconds or more.

CMake generator full path

Normally it is not necessary to specify the path to the CMake generator backend, assuming the generator executable is in environment variable $PATH or CMAKE_PROGRAM_PATH. For special use cases such as testing CMake with different versions of a generator the generator executable absolute path may be specified via CMAKE_MAKE_PROGRAM. The absolute path to the generator is necessary or CMake will not find it.

Suppose a GitHub Actions Linux image has ninja-linux.zip containing executable file “ninja”. Get the absolute path using realpath.

    - run: unzip ninja-linux.zip

    - name: CMake configure
      run: cmake -G Ninja -DCMAKE_MAKE_PROGRAM=$(realpath ./ninja) -Bbuild

CMake FindPython hints

CMake Find modules are by their nature a little aggressive about finding libraries and executables. This becomes a factor on Windows in particular when Anaconda Python is not active in the current Terminal. CMake find_package(Python) by default prefers Anaconda Python over system Python unless overridden as below. Anaconda Python won’t operate correctly without conda activate, which presumably the user has either forgotten to do or doesn’t desire at the moment. To decrease the aggressiveness and find Windows Store Python etc. when conda isn’t activated on Windows, add to the project CMakeLists.txt before find_package(Python):

set(Python_FIND_REGISTRY LAST)
# this avoids non-active conda from getting picked anyway on Windows

set(Python_FIND_VIRTUALENV STANDARD)
# Use environment variable PATH to decide preference for Python

find_package(Python)

Disable conda auto activate base

Anaconda Python by default auto-activates the “base” environment each time a new Terminal is opened. This slows opening new Terminal, particularly on systems with slow disks or virtual disks. Particularly if the user isn’t constantly using Python, it can be beneficial to make conda only active when specified. To disable conda auto-activation on new Terminal, type:

conda config --set auto_activate_base false

This setting takes effect in .condarc

CMake detect CPU model

CMake can detect the host CPU arch to use with Intel compilers. We discourage package maintainers from setting flags automatically like “-march=native” (GCC, Clang) and “-xHost” (Intel oneAPI) because they may break on user systems such as ARM or HPC. However, the user can set flags for a project by setting environment variables like CFLAGS before the first project configure in CMake. This allows optimizing for a target compiler while compiling from a different host. Or, the user on an appropriate system may simply set their ~/.profile to have CFLAGS=-march=native or similar.

Identifying Fortran compiler with CMake

Projects use a variety of methods to detect which compiler is being used to thereby set compiler options. Although this discussion focuses on Fortran, it is easily and equally applicable to other languages such as C and C++.

Robustly detect compiler in CMake CMAKE_Fortran_COMPILER_ID. This tells the compiler vendor (GNU, Intel, Clang, etc.) Don’t use CMAKE_Fortran_COMPILER because there are several compiler executables per vendor and this will not be robust over time. CMAKE_Fortran_COMPILER_VERSION allows compiler version comparisons.

Example:

if(CMAKE_Fortran_COMPILER_ID STREQUAL "IntelLLVM")
  add_compile_options("$<$<COMPILE_LANGUAGE:Fortran>:-warn:declarations;-traceback>")
elseif(CMAKE_Fortran_COMPILER_ID MATCHES "GNU|LLVMFlang")
  # Gfortran
  add_compile_options("$<$<COMPILE_LANGUAGE:Fortran>:-fimplicit-none>")
endif()

Cygwin startup environment variables

Cygwin startup configuration is controlled by Windows environment variable CYGWIN. Not populating Cygwin PATH from Windows PATH avoids confusion from Windows programs being used instead of Cygwin programs. Set Windows environment variable:

CYGWIN_NOWINPATH=1

will result in a basic Cygwin PATH like:

/usr/local/bin:/usr/bin

Look inside Cygwin “/etc/profile” for more environment variables that may be of interest.

NOTE: all Windows environment variables are imported by Cygwin. Override these variables in ~/.profile or scripts if desired.


Related: don’t populate WSL PATH from Windows PATH.

Use libutil on macOS and Linux

Libutil gives abstractions for OS-specific TTY operations. When using these abstractions across macOS and Linux, use this preprocessing statement for the appropriate header:

#ifdef __APPLE__
#include <util.h>
#else
#include <pty.h>
#endif

If using CMake, ensure the library and header are found:

find_library(UTIL_LIBRARY NAMES util)

if(APPLE)
  find_path(UTIL_INCLUDE_DIR NAMES util.h)
elseif(UNIX)
  find_path(UTIL_INCLUDE_DIR NAMES pty.h)
endif()