On macOS when using the default “AppleClang” compiler in a Fortran project where GFortran objects are linked with C/C++ objects, the ld linker may emit warnings like:
ld: warning: could not create compact unwind for ...: register .. saved somewhere other than in frame
ld: warning: could not create compact unwind for ...: registers .. and .. not saved contiguously in frame
This is an actual issue because C++ exception handling will not completely work when this warning is emitted from C++ code coupled with Fortran code.
In general, using C++ exception handling within C++ code that is linked with Fortran code will work just fine, except when this warning is issued.
The solution is to use GNU GCC C++ compiler with GFortran instead of mixing AppleClang with GFortran.
Specifying environment variable:
LDFLAGS="$LDFLAGS -Wl,-no_compact_unwind"
removes the warning, but this also disables C++ exception handling so it is not recommended.
It is possible to programmatically detect this link conflict from CMake using
try_compile.
try_compile(abi_compilePROJECTabi_checkSOURCE_DIR${CMAKE_CURRENT_LIST_DIR}/abi_checkOUTPUT_VARIABLEabi_output)if(abi_outputMATCHES"ld: warning: could not create compact unwind for") message(WARNING"C++ exception handling will not work reliably due to incompatible compilers:
C++ compiler ${CMAKE_CXX_COMPILER_ID} ${CMAKE_CXX_COMPILER_VERSION}
Fortran compiler ${CMAKE_Fortran_COMPILER_ID} ${CMAKE_Fortran_COMPILER_VERSION}" )endif()
CMake has built-in support for C/C++ static code analysis tools such as
CppCheck.
Apply CppCheck to CMake targets with
CMakeLists.txt
by setting
CMAKE_CXX_CPPCHECK.
File “cppcheck.supp” contains suppressions for false positives.
NOTE: CMake runs cppcheck from an arbitrary directory, so per-file suppressions in the file don’t work as usual.
To suppress a warning for a specific file, use the --suppress option to cppcheck in CMakeLists.txt like:
When moving between Linux systems that often default to Bash, and macOS systems that often default to
Zsh,
one may wish to change the default shell parameters.
For example, to remove duplicate entries in shell history, so that pressing “up” on repeated commands doesn’t make you press “up” repeatedly to get to the last non-duplicated command, set like the following.
Bash: ~/.inputrc: ignore duplicate lines, and omits lines that start with space.
export HISTCONTROL=ignoreboth
Zsh: ~/.zshrc: approximately the equivalent of the above Bash setting.
Users (or developers!) may not realize that the shell expands glob asterisk * unless enclosed in quotes.
This can surprise users unfamiliar with this shell behavior, say when using Python argparse with position-based arguments.
Say a user has a single file to process in a directory, and doesn’t want to type the long filename, so they type:
python myScript.py ~/data/*.h5 32
Here we assume myScript.py expects two positional arguments, the first being a filename, and the second being an integer.
If more than one “*.h5” file subsequently exists and myScript.py is run, the actual input to Python would be like:
CMake ExternalProject works for many types of sub-projects across CMake generators.
An implementation detail of Ninja is by default ExternalProject doesn’t print progress until each ExternalProject step is finished.
For large external projects that take several minutes to download and build, users could be confused thinking CMake has frozen up.
To make ExternalProject show live progress as it does with Makefiles generators, add the
USES_TERMINAL_* true
arguments to ExternalProject_Add.
CMake doesn’t print the Generator version by default.
Sometimes bugs are related to a specific generator version.
Reveal CMake generator version like this
snippet.
PyTest can work with Matlab Engine if the Matlab Engine is setup.
Use a try-catch to ensure any non-functioning Matlab Engine issue is skipped.
import pytest
deftest_me():
try:
mateng = pytest.importorskip("matlab.engine")
exceptException: # can also get RuntimeError, let's just catch all pytest.skip("Matlab engine not available")
eng = mateng.start_matlab("-nojvm")
# test code
Python subprocess can be used to run a long-running program, capturing the output to a variable and printing to the screen simultaneously.
This gives the user the comfort that the program is working OK and gives program status messages without waiting for the program to finish.
This example demonstrates the “tee” subprocess behavior.
Python subprocess can run inline multi-line Python code.
This is useful to use Python as a cross-platform demonstration or for production code where a new Python instance is called.
import subprocess
import sys
# the -u is to ensure unbuffered output so that program prints livecmd = [sys.executable, "-u", "-c", r"""
import sys
import datetime
import time
for _ in range(5):
print(datetime.datetime.now())
time.sleep(0.3)
"""]
subprocess.check_call(cmd)