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()

USB-C display adapter incompatibilities

USB-C display adapters (HDMI, DisplayPort) are a wonderful thing when they work correctly. I prefer this solution to the docking ports on old bulky laptops. A symptom is USB-C adapter works on one laptop, but not on another almost identical laptop model. Symptoms include not being detected by the operating system, to showing a black screen, or very low resolution.

The solution seems to be to stick with expensive OEM display adapters, or at least long established brands. The temptation of a cheap adapter can quickly turn to frustration or botched presentations. Another thing to watch for is cheap adapters may fail intermittently when using more than one high bandwidth feature. For example, using Gigabit Ethernet and HDMI on the cheap USB-C adapter simultaneously may fail intermittently during a conference call or teaching a class, which can be frustrating.

Workarounds

Some adapters that charge the laptop with a USB-C input for power may experience improper operations if the display adapter is plugged into the laptop while the USB-C power input is powered. This problem may persist upon re-plugging the adapter to laptop and/or power cycling the monitor and laptop. A workaround we’ve found is to unplug USB-C power input to the adapter, plug into the laptop with all the desired accessories, then finally plug USB-C power input into the adapter. That is unexpected, but has worked for us sometimes.

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-certificates.crt
  • /etc/pki/tls/certs/ca-bundle.crt
  • /etc/ssl/ca-bundle.pem

Reference


Related: Git SSL certificate location

Meld Git difftool / mergetool

Git users often use Meld to graphically resolve 2-way differences and 3-way merges.

Configure Git to use Meld:

git config --global diff.tool meld
git config --global merge.tool meld

Windows

Windows needs an additional command from PowerShell:

git config --global mergetool.meld.path "$Env:ProgramFiles\\meld\\Meld.exe"

On Windows if also using MSYS2, don’t add Meld.exe to environment variable Path as it has libstdc++.dll that conflicts with MSYS2 G++. The symptom is the G++-built executable will segfault silently.


Alternatives:

Check CMake TLS 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.

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