Scientific Computing

CMake check path write access

CMake configure time is often a convenient time to test if a directory or file is writable. It can be useful to immediately stop with message(FATAL_ERROR) if a path is not writable. For example, if CMAKE_INSTALL_PREFIX is not in a writable location – we want to fail right then and inform users what to do to correct the problem.

file(TOUCH) and file(MAKE_DIRECTORY) do not halt the configure step. Rather, if a path isn’t writable CMake only errors at the end of configure.

Example solution:

This snippet generates a fatal error with text telling the user what to try:

set(test_path /path/to/test/.ignore)
# could be done with random string filename in the desired path

execute_process(COMMAND ${CMAKE_COMMAND} -E touch ${test_path}
RESULT_VARIABLE ret
)
if(NOT ret EQUAL "0")
  message(FATAL_ERROR "No write access to ${test_path}
  <text for user to resolve issue>")
endif()

Matlab / GNU Octave SSL certificates

SSL certificate checking can add security to web operations. Some systems may need environment variable SSL_CERT_FILE for Matlab’s vendored curl. As a last resort, certificate checking can be turned off, but this raises file integrity and security issues.

Instead of disabling certificate checking set environment variable SSL_CERT_FILE to the actual certificate location.

Matlab or GNU Octave use the factory function weboptions() to control HTTP behavior for functions like websave() and webread(), including Timeout and SSL certificate.

This example sets reply timeout to 15 seconds and specifies custom SSL certificate location when environment variable SSL_CERT_FILE is set.

cert = getenv("SSL_CERT_FILE")

if isfile(cert)
  web_opts = weboptions(CertificateFilename=cert, Timeout=15);
else
  web_opts = weboptions(Timeout=15);
end

data = webread(url, opts);

Alternative: curl with Matlab

Related: Git SSL certificate location

curl certificate file location

Connecting to HTTPS servers with curl or programs using curl such as Matlab requires curl knowing the location of system certificates. If curl doesn’t know the certificates location, accessing HTTPS URLs may fail with:

curl: (77) error setting certificate verify locations: curl can't find your certificates.

Fix this problem by setting environment variable “SSL_CERT_FILE” to the location of the system certificates. Example file locations include:

/etc/ssl/certs/ca-bundle.crt
/etc/ssl/certs/ca-certificates.crt
/etc/pki/tls/certs/ca-bundle.crt
/etc/ssl/ca-bundle.pem

Reference


Related: Git SSL certificate location

Check CMake TLS SSL functioning

CMake itself is built with SSL by default. If a user mistakenly builds CMake without SSL support, this is generally not usable as the vast majority of Internet sites require SSL / TLS to function. Confusing errors result for CMake network operations like file(DOWNLOAD) in this case.

CMake has a simple capabilities check:

cmake_minimum_required(VERSION 3.25)

execute_process(COMMAND ${CMAKE_COMMAND} -E capabilities OUTPUT_VARIABLE cap)

string(JSON has_tls GET "${cap}" "tls")

message(STATUS "${CMAKE_COMMAND} TLS available: ${has_tls}")

To progamatically confirm that TLS and certificates are working, consider check_tls.

For a more complete check consider check_https.cmake

CMake resolve cyclical static link

CMake can automatically determine linker grouping via LINK_GROUP that adds linker flags like GCC:

-Wl,start-group

to static link cyclically dependent targets.

Alternatives

Target LINK_INTERFACE_MULTIPLICITY doesn’t always work. CMake docs suggest the trickiest cyclical static link cases may require Object Libraries.

A project had three targets (static libraries) that were always used like:

libfoo.a libfooC.a

or

libfoo.a libfooFortran.a

and the target code reference each other extensively, such that the linker gives up when ld –start-group isn’t used. Meson build system also adds --start-group ld option automatically.

To keep the targets with distinct compile definitions (including for “foo_src”) use CMake Object Libraries:

add_library(tmp OBJECT ${foo_src})

add_library(fooC ${c_src} $<TARGET_OBJECTS:tmp>)
add_library(fooFortran ${fortran_src} $<TARGET_OBJECTS:tmp>)

Note, there is no “libtmp” created–only the object files from the “foo_src” will be created.

Intel MPI on Windows

The Windows Intel oneAPI compilers present Visual Studio-like command line options. Intel oneAPI toolkit includes the Intel MPI library, which provides “mpiexec” needed to run MPI programs and MPI compiler wrappers.

While Windows MPI users might find using WSL for MPI more convenient and performant, even using Intel compilers in WSL, some users may prefer native Windows MPI with Intel oneAPI.

The Intel oneAPI command prompt environment can be used or use a script

Newer versions of Intel MPI have “mpiicx”, “mpiicpx” and “mpiifx” compiler wrappers.

Intel MPI on Windows is only for Intel oneAPI compiler and Visual Studio.


Although not often needed, a separate username can be used for Windows Intel MPI jobs by from Command Prompt:

runas /user:username cmd

Environment variables are not passed to the new window, so it may be necessary to run Intel compilervars.bat again. It’s possible to register the user credential in the Windows registry.

CMake link macOS Framework

macOS Frameworks such as Foundation are linked with CMAKE_LANG_LINK_LIBRARY_USING_FEATURE.

cmake_minimum_required(VERSION 3.24)

project(macosFramework LANGUAGES OBJCXX)

add_executable(main main.mm)

if(CMAKE_OBJCXX_LINK_LIBRARY_USING_FRAMEWORK_SUPPORTED)

target_link_libraries(main PRIVATE "$<LINK_LIBRARY:FRAMEWORK,Foundation>")

endif()

Example main.mm using “Foundation” macOS framework.

#import <Foundation/Foundation.h>
#include <iostream>

int main() {
    @autoreleasepool {
        NSURL *homeURL = [[NSFileManager defaultManager] homeDirectoryForCurrentUser];
        NSString *homeDirectory = [homeURL path];
        std::cout << "User home directory: " << [homeDirectory UTF8String] << "\n";
    }
    return 0;
}
cmake -Bbuild

cmake --build build -v

Shows the link line used.

Obsolete syntax

The obsolete, pre-CMake 3.24 syntax is like:

target_link_libraries(main PRIVATE
"-framework Foundation"
"-framework IOKit"
)

Cray compiler CMake toolchain

Cray PE can select from multiple compilers as backends for better language standard support while maintaining performance of Cray frontend optimizations. Compilers such as Intel oneAPI themselves use GCC as a backend on Linux. Manual configuration may be required as the default system GCC may be too old for the desired language standard features. Or, the libstdc++ can be too old in the system default GCC. These issues are remediated by purposeful specification of the Cray-Intel-GCC toolchain in a CMake toolchain file.

This toolchain file can be copied to a common location like ~ and used among many projects, such as cray.cmake.

For CMake project that have ExternalProject inside them, there must be a CMAKE_TOOLCHAIN_FILE parameter to ExternalProject_Add like:

set(cmake_args ...)

if(CMAKE_TOOLCHAIN_FILE)
  list(APPEND cmake_args -DCMAKE_TOOLCHAIN_FILE:FILEPATH=${CMAKE_TOOLCHAIN_FILE})
endif()


ExternalProject_Add(...
CMAKE_ARGS ${cmake_args}
)

The CMake project is configured like:

cmake --toolchain ~/cray.cmake -B build

Intel oneMKL LAPACK95 with Gfortran

On Linux, the Intel oneMKL LAPACK95 library can also be used with Gfortran. Build and install LAPACK95 with Intel MKL Lapack95 project.

An example CMakeLists.txt, using the FindLAPACK.cmake under cmake/ of Netlib LAPACK95

list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake")

find_package(LAPACK COMPONENTS LAPACK95 REQUIRED)

add_executable(myexe myprogram.f90)
target_link_libraries(myexe PRIVATE LAPACK::LAPACK95)