Configure cmake to work with homebrew libraries instead system-provided libraries - cmake

I find myself going against the grain configuring cmake paths with ccmake over and over again as with every change of for ex. compiler some of my library paths get lost.
In particular paths to (unlinked) lapack, lapacke, gsl get either lost or set to system defaults instead the ones I've installed with brew.
There has to be a way to tell cmake to "ignore" system libraries and instead look in homebrew paths (say. /opt/homebrew/lib, /opt/homebrew/include etc.).
I'd prefer not to link those libraries as this is not recommend and I'm not experienced in switching environments.
[EDIT] MRE:
git clone https://gitlab.physik.uni-muenchen.de/AG-Scrinzi/tRecX.git
cd tRecX
cmake . -DCMAKE_BUILD_TYPE=Parallel
make -j 8
I add the following to .bash_profile/.zshrc:
export LDFLAGS="-L/opt/homebrew/opt/lapack/lib -L/opt/homebrew/opt/lapack/lib"
export CPPFLAGS="-I/opt/homebrew/opt/lapack/include -I/opt/homebrew/opt/openblas/include"
export PKG_CONFIG_PATH="/opt/homebrew/opt/lapack/lib/pkgconfig /opt/homebrew/opt/openblas/lib/pkgconfig"
then I try:
cmake . -DCMAKE_PREFIX_PATH=/opt/homebrew -DCMAKE_FIND_FRAMEWORK=NEVER -DCMAKE_FIND_APPBUNDLE=NEVER -DCMAKE_FIND_USE_CMAKE_SYSTEM_PATH=FALSE -DCMAKE_FIND_USE_SYSTEM_ENVIRONMENT_PATH=FALSE -DMPI_CXX_COMPILER=/opt/homebrew/bin/mpicxx -DMPI_C_COMPILER=/opt/homebrew/bin/mpicc -DCMAKE_CXX_COMPILER=/opt/homebrew/bin/g++-11 -DCMAKE_C_COMPILER=/opt/homebrew/bin/gcc-11

The most common solution is to just set CMAKE_PREFIX_PATH to /opt/homebrew. CMake will then look preferentially in /opt/homebrew for everything. Since you're on Apple, you might need to set CMAKE_FIND_FRAMEWORK and CMAKE_FIND_APPBUNDLE to LAST or NEVER, too.
You can skip the standard platform search paths by setting CMAKE_FIND_USE_CMAKE_SYSTEM_PATH to FALSE at the command line, in a preset, or in a toolchain file. You might also wish to disable looking at the PATH environment variable by setting CMAKE_FIND_USE_SYSTEM_ENVIRONMENT_PATH to FALSE.
Finally, if you're in a cross-compiling scenario or toolchain file, you can change the definition of the system directories by setting CMAKE_SYSROOT. Note that the sysroot will have to contain the language runtime libraries (e.g. glibc) and will be passed to the --sysroot flag (or equivalent). Just be aware of those effects, too.
All of this is documented here:
https://cmake.org/cmake/help/latest/command/find_package.html#search-procedure
https://cmake.org/cmake/help/latest/variable/CMAKE_FIND_FRAMEWORK.html#variable:CMAKE_FIND_FRAMEWORK
https://cmake.org/cmake/help/latest/variable/CMAKE_FIND_APPBUNDLE.html#variable:CMAKE_FIND_APPBUNDLE
The following homebrew.cmake toolchain file worked for me:
set(HOMEBREW_PREFIX "/usr/local"
CACHE PATH "Path to Homebrew installation")
set(CMAKE_C_COMPILER "${HOMEBREW_PREFIX}/bin/gcc-11")
set(CMAKE_CXX_COMPILER "${HOMEBREW_PREFIX}/bin/g++-11")
set(CMAKE_PREFIX_PATH
"${HOMEBREW_PREFIX}"
# These libraries are keg-only and not loaded into
# the root prefix by default (to avoid clashes).
"${HOMEBREW_PREFIX}/opt/lapack"
"${HOMEBREW_PREFIX}/opt/openblas"
"${HOMEBREW_PREFIX}/opt/gcc/lib/gcc/11"
)
list(TRANSFORM CMAKE_PREFIX_PATH APPEND "/include"
OUTPUT_VARIABLE CMAKE_CXX_STANDARD_INCLUDE_DIRECTORIES)
set(CMAKE_C_STANDARD_INCLUDE_DIRECTORIES "${CMAKE_CXX_STANDARD_INCLUDE_DIRECTORIES}")
set(CMAKE_FIND_FRAMEWORK NEVER)
set(CMAKE_FIND_APPBUNDLE NEVER)
set(CMAKE_FIND_USE_CMAKE_SYSTEM_PATH FALSE)
set(CMAKE_FIND_USE_SYSTEM_ENVIRONMENT_PATH FALSE)
I built with the following commands:
$ ls
tRecX homebrew.cmake
$ cmake -G Ninja -S tRecX -B tRecX-build \
-DCMAKE_TOOLCHAIN_FILE=$PWD/homebrew.cmake \
-DCBLAS=/usr/local/opt/openblas/lib/libblas.dylib \
-DCMAKE_EXE_LINKER_FLAGS="-Wl,-undefined,dynamic_lookup" \
-DCMAKE_SHARED_LINKER_FLAGS="-Wl,-undefined,dynamic_lookup" \
-DCMAKE_BUILD_TYPE=Parallel
[ ... output clipped ... ]
Boost found -- full functionality
Build "Parallel" with C++ flags -D_USE_BOOST_ -O3 -pthread -D_USE_FFTW_, return to default by -UCMAKE_BUILD_TYPE
Compiler: /usr/local/bin/g++-11, change by -DCMAKE_CXX_COMPILER=[path_to_complier]
-- Linking to libraries Boost::system;Boost::filesystem;/usr/local/lib/libfftw3.dylib;/usr/local/opt/gcc/lib/gcc/11/libgfortran.dylib;alglib;/usr/local/lib/libarpack.dylib;Boost::system;Boost::filesystem;/usr/local/opt/lapack/lib/liblapacke.dylib;/usr/local/opt/openblas/lib/libblas.dylib;/usr/local/opt/lapack/lib/liblapack.dylib;/usr/local/opt/lapack/lib/libblas.dylib;m
-- Configuring done
-- Generating done
-- Build files have been written to: /Users/alexreinking/Development/tRecX-build
$ cmake --build tRecX-build
I had to set CBLAS manually because libblas.dylib provides the OpenBLAS CBLAS interface, but the build system specifically looks for a library named libcblas. There's no other option in this case.
The code and build have issues with its linking model and dependencies. I was able to paper over these by setting -Wl,-undefined,dynamic_lookup. However, note that this will just defer linker errors to runtime and might impose a large startup cost.
If you can make commits to the project, I would store these settings in a preset, maybe name it homebrew-parallel or something:
-DCMAKE_TOOLCHAIN_FILE=$PWD/homebrew.cmake \
-DCBLAS=/usr/local/opt/openblas/lib/libblas.dylib \
-DCMAKE_EXE_LINKER_FLAGS="-Wl,-undefined,dynamic_lookup" \
-DCMAKE_SHARED_LINKER_FLAGS="-Wl,-undefined,dynamic_lookup" \
-DCMAKE_BUILD_TYPE=Parallel
Then you could just run cmake --preset=homebrew-parallel

Related

generating debug info with emscripten / ninja / cmake on complex project

I am trying to debug a port of some c and c++ code to WASM. I worked out how to source level debug in the browser with a simple 10 line .c program but now I want to make that work with a non trivial code base. (mixed c and c++). The wasm code works in a simple app but not in my more complex use case, hence the need to debug it
I use CMake to generate ninja build files
Here is where I am setting flags in my CMakeLists.txt
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} \
-s MODULARIZE=1 \
-s SINGLE_FILE=1 \
-s EXPORT_NAME=aubio \
-g --bind")
this was basically copied from the original codebase (the -g instead of -Oz is mine), I am not a CMake nor ninja nor emscripten wizard. When I build this I can see that the CXX flags are not passed to the emc++ compile passes, only to the 'linker' phase
I am not even sure where the -g (perhaps with source-map) needs to be for a multi-file project 'linked' into a single file. Should it be on the compile passes or the link pass , or maybe both. But certainly at the moment I do not get any symbols anywhere, no 'map' file(s) (embedded DWARF?, since the browser plugin claims to support it)
set(CMAKE_BUILD_TYPE Debug)
seems to embed DWARF to WASM file.
I don't know why set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g") nor target_compile_options(foo PUBLIC -g) doesn't work in Release build.

cmake building in source directory, not PWD

The question
Debug vs Release in CMake
indicates that
cd ~/codebase
mkdir Release
cd Release
cmake -DCMAKE_BUILD_TYPE=Release ..
make
Will create the Makefile in release, and build the binary there. The intermediate .o files will be in a subdirectory of this.
However, when I do this with my project, CMake ignores the PWD that it is started from. The final target is always the directory ~/codebase/ which contains CMakeList.txt.
In the cmake-gui tool, I specified the source and build directories to be the same directory, the FQN to codebase
I'm new to CMake, and don't know how to get this to work as I expect. What should I modify to get this work as expected?
If you are using a single configuration generator (Ninja/Unix-Makefiles)
Then you need a build folder for each configuration.
Like this:
# Configure the build
cmake -S . -B build/Debug -D CMAKE_BUILD_TYPE=Release
# Actually build the binaries
cmake --build build/Debug
For multi-configuration generators it's slightly different (Ninja Multi-Config, Visual Studio)
# Configure the build
cmake -S . -B build
# Actually build the binaries
cmake --build build --config Debug
If you are wondering why this is necessary it's because cmake isn't a build system. It's a meta-build system (IE a build system that creates build systems). This is basically the result of handling build systems that support multiple-configurations in 1 build. If you'd like a deeper understanding I'd suggest reading a bit about cmake in Craig Scott's book "Professional CMake: A Practical Guide
Note:
My examples use newer cmake cli practices.
EDIT:
That question you linked to has dangerously out of date answers...

What command in Equivalent of ./configure --help in cmake? [duplicate]

How can I list cmake default build option in command-line?
I need to build OpenCV libraries from source. Before that, I want to know what are the default build settings.
cmake -LAH
To list all option(...) and set(... CACHE ...) variables, including those marked as advanced, do:
cmake -LAH
where:
-L: list variables
-A: include advanced variables.
CMake has a few dozen advanced variables defined as default, and you can mark you own variables as advanced with mark_as_advanced). Some default CMake advanced variables include basic default compilation parameters such as:
CMAKE_CXX_COMPILER:FILEPATH=/usr/bin/c++
CMAKE_CXX_FLAGS:STRING=
CMAKE_CXX_FLAGS_DEBUG:STRING=-g
If you are only interested in the main configuration options of some project, you will likely want to remove the -A as it would be mostly noise.
-H: include help strings. -H was previously mentioned at: https://stackoverflow.com/a/53075317/895245 consider upvoting that answer
Example
CMakeLists.txt
cmake_minimum_required(VERSION 3.0)
project(ProjectName)
set(GREETING "hello" CACHE STRING "How to greet")
set(GREETING2 "hello2" CACHE STRING "Supersecret greeting")
mark_as_advanced(FORCE VAR GREETING2)
set(MYNOCACHE "mynocacheval")
option(WORLD "Print world or not?" ON)
If we run:
mkdir -p build
cd build
cmake -LAH ..
the output contains:
// How to greet
GREETING:STRING=hello
// Supersecret greeting
GREETING2:STRING=hello2
// How to greet
MSG:STRING=hello
// Supersecret greeting
MSG2:STRING=hello2
// Print world or not?
WORLD:BOOL=ON
plus a bunch of default defined CMake variables. If we remove -A we get only:
// Choose the type of build, options are: None Debug Release RelWithDebInfo MinSizeRel ...
CMAKE_BUILD_TYPE:STRING=debug
// Install path prefix, prepended onto install directories.
CMAKE_INSTALL_PREFIX:PATH=/usr/local
// How to greet
GREETING:STRING=hello
// How to greet
MSG:STRING=hello
// Print world or not?
WORLD:BOOL=ON
so we see that our advanced variable GREETING2 is not present. We also understand that CMake feels that two of their default variables are often useful to merit the non-advanced distinction:
CMAKE_BUILD_TYPE to control debug vs release: Debug vs Release in CMake
CMAKE_INSTALL_PREFIX to decide where to install the project output
Without -H we get just:
CMAKE_BUILD_TYPE:STRING=debug
CMAKE_INSTALL_PREFIX:PATH=/usr/local
GREETING:STRING=hello
MSG:STRING=hello
WORLD:BOOL=ON
Note that the values are the cached values, not the defaults. E.g. if we first set a cached value:
cmake -DGREETING=bye ..
then running again cmake -L .. gives:
CMAKE_BUILD_TYPE:STRING=debug
CMAKE_INSTALL_PREFIX:PATH=/usr/local
GREETING:STRING=bye
MSG:STRING=hello
WORLD:BOOL=ON
Better way to determine the exact build options: run a verbose build!
I think some of people coming to this question are trying to understand how CMake is building their things exactly.
While you could deduce much of that from cmake -LA, a better more direct and sure-fire way would be as per: Using CMake with GNU Make: How can I see the exact commands? to just build with with:
make VERBOSE=1
The output would then contain a line of type:
/usr/bin/cc -DGREETING=\"hello\" -DWORLD -MD -MT CMakeFiles/main.dir/main.c.o -MF CMakeFiles/main.dir/main.c.o.d -o CMakeFiles/main.dir/main.c.o -c /home/ciro/main.c
which makes it clear exactly what CMake is doing.
ccmake ncurses
ccmake is an nCurses Cmake UI. The advantage over cmake -L is that you can interactively set the values as you find them:
sudo apt-get install cmake-curses-gui
ccmake .
shows:
To see the advanced options from cmake-curses-gui you can just enter the t key as mentioned on the UI which toggles them on or off.
cmake-gui
This UI is a bit better than ccmake in terms of capabilities:
sudo apt install cmake-qt-gui
cmake-gui .
we have:
"Advanced" checkbox to show the advanced options
"Grouped" checkbox to group options. By default it produces two categories:
"CMAKE" for the "CMAKE" default options
"Ungrouped Entries" for your variables
Option groups are apparently generated automatically based on common option name prefixes: Creating groups of CMake options
Tested in Ubuntu 22.10, cmake 3.5.2.
You can do cmake -LAH too. The H flag will provide you help for each option.
I do not know of an direct way to do it.
A way around this is to edit the main CMakeLists.txt and print at the end of the file the settings you are interested. The Variables where the most important cmake setting are stored are listed here:
I always print these variables at the end of my CMakeLists.txt to see the settings.
MESSAGE(STATUS "Build type: " ${CMAKE_BUILD_TYPE})
MESSAGE(STATUS "Library Type: " ${LIB_TYPE})
MESSAGE(STATUS "Compiler flags:" ${CMAKE_CXX_COMPILE_FLAGS})
MESSAGE(STATUS "Compiler cxx debug flags:" ${CMAKE_CXX_FLAGS_DEBUG})
MESSAGE(STATUS "Compiler cxx release flags:" ${CMAKE_CXX_FLAGS_RELEASE})
MESSAGE(STATUS "Compiler cxx min size flags:" ${CMAKE_CXX_FLAGS_MINSIZEREL})
MESSAGE(STATUS "Compiler cxx flags:" ${CMAKE_CXX_FLAGS})

Set multiple paths to CMAKE_Fortran_MODULE_DIRECTORY

So I am trying to include an installed Fortran library to a CMake project. I know the directory where the module (.mod) file is located, but my project can't seem to find it unless I set CMAKE_Fortran_MODULE_DIRECTORY.
SET(LIB_INCLUDE_DIR /usr/local/include)
SET(EX_FILES main.f90 file1.f90 file2.f90)
INCLUDE_DIRECTORIES(${LIB_INCLUDE_DIR})
ADD_EXECUTABLE(test ${EX_FILES})
TARGET_LINK_LIBRARIES(test lib1)
Where the error is
use lib1
1
Fatal Error: Can't open module file 'lib1.mod' for reading at (1): No such file or directory
unless I include the line
SET(CMAKE_Fortran_MODULE_DIRECTORY ${LIB_INCLUDE_DIR})
And then it can find the file just fine. But I'm running into a little problem. By setting CMAKE_Fortran_MODULE_DIRECTORY, CMake tries to write all generated modules to this directory rather than the CMAKE_BINARY_DIR (where I would like it).
From the documentation, I know that CMAKE_Fortan_MODULE_DIRECTORY is meant to be set to specify where to write generated module files, but some compilers look to that directory to find modules. Is there any way to set multiple directories so that if it can't find in/write to one directory, it searches the second? When I try to set CMAKE_Fortran_MODULE_DIRECTORY to be multiple directories, it only looks at the first directory.
If it helps I am on a Ubuntu 14.04 LTS system using gfortran 4.8.4
EDIT:
So by Alexander Vogt's suggestion I ran with VERBOSE=1 and got
cd /home/user/Repos/build/src && gfortran -I/home/user/Repos/build/src -isystem /usr/local/include -c /home/user/Repos/test_project/src/main.f90 -o CMakeFiles/test.dir/main.f90.o
when I did NOT set CMAKE_Fortran_MODULE_DIRECTORY and
cd /home/user/Repos/build/src && gfortran -J/usr/local/include -I/home/user/Repos/build/src -isystem /usr/local/include -c /home/user/Repos/test_project/src/main.f90 -o CMakeFiles/test.dir/main.f90.o
when I did.
It seems the only difference is the -J flag, which sets exactly what CMAKE_Fortran_MODULE_DIRECTORY sets. Is there some flag that sets just where to look for compiled modules, and not where to put them?

How to list all CMake build options and their default values?

How can I list cmake default build option in command-line?
I need to build OpenCV libraries from source. Before that, I want to know what are the default build settings.
cmake -LAH
To list all option(...) and set(... CACHE ...) variables, including those marked as advanced, do:
cmake -LAH
where:
-L: list variables
-A: include advanced variables.
CMake has a few dozen advanced variables defined as default, and you can mark you own variables as advanced with mark_as_advanced). Some default CMake advanced variables include basic default compilation parameters such as:
CMAKE_CXX_COMPILER:FILEPATH=/usr/bin/c++
CMAKE_CXX_FLAGS:STRING=
CMAKE_CXX_FLAGS_DEBUG:STRING=-g
If you are only interested in the main configuration options of some project, you will likely want to remove the -A as it would be mostly noise.
-H: include help strings. -H was previously mentioned at: https://stackoverflow.com/a/53075317/895245 consider upvoting that answer
Example
CMakeLists.txt
cmake_minimum_required(VERSION 3.0)
project(ProjectName)
set(GREETING "hello" CACHE STRING "How to greet")
set(GREETING2 "hello2" CACHE STRING "Supersecret greeting")
mark_as_advanced(FORCE VAR GREETING2)
set(MYNOCACHE "mynocacheval")
option(WORLD "Print world or not?" ON)
If we run:
mkdir -p build
cd build
cmake -LAH ..
the output contains:
// How to greet
GREETING:STRING=hello
// Supersecret greeting
GREETING2:STRING=hello2
// How to greet
MSG:STRING=hello
// Supersecret greeting
MSG2:STRING=hello2
// Print world or not?
WORLD:BOOL=ON
plus a bunch of default defined CMake variables. If we remove -A we get only:
// Choose the type of build, options are: None Debug Release RelWithDebInfo MinSizeRel ...
CMAKE_BUILD_TYPE:STRING=debug
// Install path prefix, prepended onto install directories.
CMAKE_INSTALL_PREFIX:PATH=/usr/local
// How to greet
GREETING:STRING=hello
// How to greet
MSG:STRING=hello
// Print world or not?
WORLD:BOOL=ON
so we see that our advanced variable GREETING2 is not present. We also understand that CMake feels that two of their default variables are often useful to merit the non-advanced distinction:
CMAKE_BUILD_TYPE to control debug vs release: Debug vs Release in CMake
CMAKE_INSTALL_PREFIX to decide where to install the project output
Without -H we get just:
CMAKE_BUILD_TYPE:STRING=debug
CMAKE_INSTALL_PREFIX:PATH=/usr/local
GREETING:STRING=hello
MSG:STRING=hello
WORLD:BOOL=ON
Note that the values are the cached values, not the defaults. E.g. if we first set a cached value:
cmake -DGREETING=bye ..
then running again cmake -L .. gives:
CMAKE_BUILD_TYPE:STRING=debug
CMAKE_INSTALL_PREFIX:PATH=/usr/local
GREETING:STRING=bye
MSG:STRING=hello
WORLD:BOOL=ON
Better way to determine the exact build options: run a verbose build!
I think some of people coming to this question are trying to understand how CMake is building their things exactly.
While you could deduce much of that from cmake -LA, a better more direct and sure-fire way would be as per: Using CMake with GNU Make: How can I see the exact commands? to just build with with:
make VERBOSE=1
The output would then contain a line of type:
/usr/bin/cc -DGREETING=\"hello\" -DWORLD -MD -MT CMakeFiles/main.dir/main.c.o -MF CMakeFiles/main.dir/main.c.o.d -o CMakeFiles/main.dir/main.c.o -c /home/ciro/main.c
which makes it clear exactly what CMake is doing.
ccmake ncurses
ccmake is an nCurses Cmake UI. The advantage over cmake -L is that you can interactively set the values as you find them:
sudo apt-get install cmake-curses-gui
ccmake .
shows:
To see the advanced options from cmake-curses-gui you can just enter the t key as mentioned on the UI which toggles them on or off.
cmake-gui
This UI is a bit better than ccmake in terms of capabilities:
sudo apt install cmake-qt-gui
cmake-gui .
we have:
"Advanced" checkbox to show the advanced options
"Grouped" checkbox to group options. By default it produces two categories:
"CMAKE" for the "CMAKE" default options
"Ungrouped Entries" for your variables
Option groups are apparently generated automatically based on common option name prefixes: Creating groups of CMake options
Tested in Ubuntu 22.10, cmake 3.5.2.
You can do cmake -LAH too. The H flag will provide you help for each option.
I do not know of an direct way to do it.
A way around this is to edit the main CMakeLists.txt and print at the end of the file the settings you are interested. The Variables where the most important cmake setting are stored are listed here:
I always print these variables at the end of my CMakeLists.txt to see the settings.
MESSAGE(STATUS "Build type: " ${CMAKE_BUILD_TYPE})
MESSAGE(STATUS "Library Type: " ${LIB_TYPE})
MESSAGE(STATUS "Compiler flags:" ${CMAKE_CXX_COMPILE_FLAGS})
MESSAGE(STATUS "Compiler cxx debug flags:" ${CMAKE_CXX_FLAGS_DEBUG})
MESSAGE(STATUS "Compiler cxx release flags:" ${CMAKE_CXX_FLAGS_RELEASE})
MESSAGE(STATUS "Compiler cxx min size flags:" ${CMAKE_CXX_FLAGS_MINSIZEREL})
MESSAGE(STATUS "Compiler cxx flags:" ${CMAKE_CXX_FLAGS})