Issue with find_package (boost) when specifying BOOST_ROOT - cmake

I am trying to build gnucash on ubuntu with some updated boost libs. I am using cmake-3.21.1 but have also tried with 3.16.3.
I want to link/include against boost 1.75. In order to do that i built boost as (all the gory details):
- sudo mkdir -p /opt/software/boost/boost_1_75
- sudo chmod -R 755 /opt/software
- cd /opt/software/boost/boost_1_75
- wget -O boost_1_75_0.tar.gz https://sourceforge.net/projects/boost/files/boost/1.75.0/boost_1_75_0.tar.gz/download
- tar -xzvf boost_1_75_0.tar.gz
- cd boost_1_75
- ./bootstrap.sh --prefix=/opt/software
- ./b2
- ./b2 install
which will give me (as expected) directories
- /opt/software/include/boost
- /opt/software/lib/libboost*
So far, so good.
Now i try to configure gnucash as follows (extracted gnucash code resides in $SRCROOT/gnucash):
- cd $SRCROOT
- mkdir gnucash-build
- cd gnucash-build
- export BOOST_ROOT=/opt/software; export CC=/usr/bin/clang; export CXX=/usr/bin/clang++; /opt/software/cmake/cmake-3.21.1/bin/cmake -DBOOST_ROOT=$BOOST_ROOT $SRCROOT/gnucash-build
The relevant section in the CMakeLists.txt is
if (NOT DEFINED ${BOOST_ROOT})
set(BOOST_ROOT $ENV{BOOST_ROOT})
find_package (Boost COMPONENTS date_time regex locale filesystem system program_options)
message(STATUS "1.1: ${BOOST_ROOT}")
else()
find_package (Boost 1.67.0 COMPONENTS date_time regex locale filesystem system program_options)
message(STATUS "1.2: ${BOOST_ROOT}")
endif()
message(STATUS "2: Boost_INCLUDE_DIRS: ${Boost_INCLUDE_DIRS}")
Running
export BOOST_ROOT=/opt/software; export CC=/usr/bin/clang; export CXX=/usr/bin/clang++; /opt/software/cmake/cmake-3.21.1/bin/cmake -DBOOST_ROOT=$BOOST_ROOT $SRCROOT/gnucash-build
gives me:
1.1: /opt/software
2: Boost_INCLUDE_DIRS: /usr/include
so i know it enters the correct case.
However, Boost_INCLUDE_DIRS should be /opt/software/include/boost and not '/usr/include'
I also tried without (default) and with (which i added):
cmake_policy(SET CMP0074 NEW)
Neither appears to work.
I am not sure on how to about debugging this issue. Likely i am doing something wrong here.
Any pointers are greatly appreciated.
EDIT 1
Doing find_package (Boost 1.75.0 COMPONENTS date_time regex locale filesystem system program_options)
instead of
find_package (Boost COMPONENTS date_time regex locale filesystem system program_options)
will actually do what i want.
However, i would have expected that, without specifying the exact version, by specifying BOOST_ROOT, the cmake compiler will first look into the specified directory and take whatever version it finds there and use it.
From the docs (https://cmake.org/cmake/help/latest/module/FindBoost.html):
BOOST_ROOT, BOOSTROOT
Preferred installation prefix.

Related

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

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

What is the proper way to handle `CMAKE_INSTALL_PREFIX` when using the Ninja Multi-Config cmake generator?

With the cmake generator "Ninja Multi-Config" what is the proper way to handle CMAKE_INSTALL_PREFIX. For instance, if you do:
$ cmake -DCMAKE_INSTALL_PREFIX=../install -G "Ninja Multi-Config" ..
$ cmake --build . --config Release --target install
And then afterwards do
$ cmake --build . --config Debug --target install
will the files in ../install be overwritten by the Debug install? What is the normal way to handle the install location in such cases?
By default they will be overwritten- Ie. with multi-config, the configurations' files install to the same locations.
Command-line "manual" approach
If you don't mind having to do this kind of thing manually on the command-line each time you install, you can just use the --prefix parameter for cmake --install <...>.
From the docs for CMAKE_INSTALL_PREFIX:
The CMAKE_INSTALL_PREFIX may be defined when configuring a build tree to set its installation prefix. Or, when using the cmake(1) command-line tool's --install mode, one may specify a different prefix using the --prefix option.
In that sense, CMAKE_INSTALL_PREFIX can be seen as a default value set per-generated buildsystem that can be overridden on the commandline.
So you can do something like cmake --install <build_dir> --config <config> --prefix <install_dir_unique_to_config>.
defaults in CMakeLists.txt approach
See this CMake mailing thread for various workarounds. Summarized here:
You can (with some exceptions- see the docs) use the <CONFIG>_POSTFIX target property to append a postfix to an output name of a target.
set_target_properties(my_target <more targets can be listed here> PROPERTIES
DEBUG_POSTFIX "-debug"
RELEASE_POSTFIX "-release"
# etc.
)
Workaround using install(DESTINATION) parameters:
install(TARGETS ${LIB_NAME}
CONFIGURATIONS DEBUG
EXPORT ${LIB_NAME}Config-d
PUBLIC_HEADER DESTINATION "include/${LIB_NAME}"
LIBRARY DESTINATION "bin/${LIB_NAME}/debug/"
ARCHIVE DESTINATION "lib/${LIB_NAME}/debug"
)
install(TARGETS ${LIB_NAME}
CONFIGURATIONS RELEASE
EXPORT ${LIB_NAME}Config
PUBLIC_HEADER DESTINATION "include/${LIB_NAME}"
LIBRARY DESTINATION "bin/${LIB_NAME}/release/"
ARCHIVE DESTINATION "lib/${LIB_NAME}/release/"
)

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?

What is INSTALL_DIR useful for in ExternalProject_Add command?

I don't understand the usage of INSTALL_DIR in ExternalProject_Add command. I try to use it but it does not seem to work. Here is an example of a CMakeLists.txt, using Eigen library which compiles quickly:
cmake_minimum_required (VERSION 2.6)
project (example CXX)
include(ExternalProject)
include(ProcessorCount)
set(CMAKE_VERBOSE_MAKEFILE ON)
ProcessorCount(N)
if(NOT N EQUAL 0)
set(CMAKE_BUILD_FLAGS -j${N})
endif()
ExternalProject_Add
(
mylib
PREFIX myprefix
DOWNLOAD_COMMAND wget http://bitbucket.org/eigen/eigen/get/3.2.4.tar.gz && tar xvzf 3.2.4.tar.gz -C mylib --strip-components=1
)
I chose the following project hierarchy:
project
CMakeLists.txt
build/
From build repository, I type:
cmake ..
make
The installation process fails with the following message:
file cannot create directory: /usr/local/include/eigen3.
Maybe need administrative privileges.
As far as I understand, it means that I need to define a "prefix" during the configuration step:
cmake -D CMAKE_INSTALL_PREFIX=$INSTALL_DIR ..
But, the INSTALL_DIR variable is already defined in the ExternalProject_Add command. However, I get the same error when I modify the value of INSTALL_DIR by adding
INSTALL_DIR myprefix/src/install
in the ExternalProject_Add command.
So, what is INSTALL_DIR useful for?
What am I doing wrong?
Of course, I know how to provide my own configuration command to add a prefix and solve the problem. But it is not my question. My question is: if I have to do that, what is the purpose of INSTALL_DIR?
From what I found in this discussion https://www.mail-archive.com/cmake#cmake.org/msg51663.html (scroll to the end of the page to navigate through the thread messages) it is indeed pretty common thing to use CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${CMAKE_BINARY_DIR}/contrib
Furthermore, lurking through the ExternalProject.cmake module I found out that the only effect setting this directory has is that CMake will create directory specified in INSTALL_DIR before doing anything else.
Also, it will set the property that you can gather through ExternalProject_Get_Property(${project_name} install_dir) command.
And that's pretty much it.
// As of CMake version 3.2.2

What is cmake_install.cmake

I wrote a very simple HelloWorld.c program and ran Cmake. It created a cmake_install.cmake file in my build directory. Can somebody explain to me why CMake generated the file cmake_install.cmake? What is it's purpose and how can I use it?
CMakelists.txt :
cmake_minimum_required(VERSION 3.0)
PROJECT(FirstExample)
add_executable(prog first.c)
Thanks!
You generally don't use cmake_install.cmake directly. From the v3.12 page it states:
The install() command generates a file, cmake_install.cmake, inside
the build directory, which is used internally by the generated install
target and by CPack.
With your current CMakeLists.txt, the generated file doesn't do much. To create a useful install you would need to add more INSTALL commands to your CMakeLists.txt using the syntax below.
INSTALL(TARGETS targets... [EXPORT <export-name>]
[[ARCHIVE|LIBRARY|RUNTIME|FRAMEWORK|BUNDLE|
PRIVATE_HEADER|PUBLIC_HEADER|RESOURCE]
[DESTINATION <dir>]
[INCLUDES DESTINATION [<dir> ...]]
[PERMISSIONS permissions...]
[CONFIGURATIONS [Debug|Release|...]]
[COMPONENT <component>]
[OPTIONAL] [NAMELINK_ONLY|NAMELINK_SKIP]
] [...])
For further reading on this command, check out the documentation site and wiki.
If it's desired to manually execute the script as stated by Nic30g the 3.12 page states that cmake -P accepts the following variables:
COMPONENT
Set this variable to install only a single CPack component as opposed to all of them. For example, if you only want to install the Development component, run
cmake -DCOMPONENT=Development -P cmake_install.cmake
BUILD_TYPE
Set this variable to change the build type if you are using a multi-config generator. For example, to install with the Debug configuration, run
cmake -DBUILD_TYPE=Debug -P cmake_install.cmake.
DESTDIR
This is an environment variable rather than a CMake variable. It allows you to change the installation prefix on UNIX systems. See DESTDIR for details.
As previous answer tells, the cmake_install.cmake contains the commands generated by install command from your CMakeLists.txt.
You can execute it by cmake -P cmake_install.cmake and it performs the installation of your project even on windows.
https://cmake.org/pipermail/cmake/2007-April/013657.html