I know that in order to set a variable, we do -DVARIABLE=VALUE, but what if I need to unset it?
I tried -DVARIABLE=FALSE but it didn't work, the compiler complains about what does FALSE means
The magic flag is -U. Trimmed output:
$ grep DOCS CMakeCache.txt
HOUSEGUEST_BUILD_DOCS:BOOL=OFF
$ cmake -UHOUSEGUEST_BUILD_DOCS .
-- Configuring done
-- Generating done
-- Build files have been written to: /my/build/folder
$ !grep
grep DOCS CMakeCache.txt
HOUSEGUEST_BUILD_DOCS:BOOL=ON
From cmake --help:
-U <globbing_expr> = Remove matching entries from CMake cache.
Related
I know that in order to set a variable, we do -DVARIABLE=VALUE, but what if I need to unset it?
I tried -DVARIABLE=FALSE but it didn't work, the compiler complains about what does FALSE means
The magic flag is -U. Trimmed output:
$ grep DOCS CMakeCache.txt
HOUSEGUEST_BUILD_DOCS:BOOL=OFF
$ cmake -UHOUSEGUEST_BUILD_DOCS .
-- Configuring done
-- Generating done
-- Build files have been written to: /my/build/folder
$ !grep
grep DOCS CMakeCache.txt
HOUSEGUEST_BUILD_DOCS:BOOL=ON
From cmake --help:
-U <globbing_expr> = Remove matching entries from CMake cache.
I have seen the following way of setting CMAKE_CXX_FLAGS in the toolchain file:
SET(CMAKE_CXX_FLAGS "-m32" CACHE STRING "C++ compiler flags" FORCE)
Should I use it in the toolchain file instead of
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -m32")
?
What are differences between them ?
tl;dr: there are two acceptable ways of doing this.
First, and most of the time (90%+), you can use the _INIT variables as suggested by the documentation:
set(CMAKE_CXX_FLAGS_INIT "-m32")
Second, if CMake is adding incorrect/conflicting flags for your compiler/platform combination, you can override it completely by setting the cache variable without FORCE.
set(CMAKE_CXX_FLAGS "-m32" CACHE STRING "C++ compiler flags")
Read on for further details.
Let's run a few experiments. We'll use the following CMakeLists.txt:
cmake_minimum_required(VERSION 3.23)
project(test LANGUAGES CXX)
message(STATUS "CMAKE_CXX_FLAGS_DEBUG = ${CMAKE_CXX_FLAGS_DEBUG}")
On most systems, CMake leaves CMAKE_CXX_FLAGS blank by default. The main exception is Windows with MSVC, where it adds /EHsc and (on older versions) /GR to ensure that standard C++ exception handling and RTTI are enabled.
Since I don't have ready access to a Windows system, I use CMAKE_CXX_FLAGS_DEBUG, which does have default-initialized flags on most compilers. The same principles apply, though, since it is the responsibility of the platform module to set these in both cases.
Experiment 1: No toolchain file
$ cmake -S . -B build
-- The CXX compiler identification is GNU 11.2.0
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: /usr/bin/c++ - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- CMAKE_CXX_FLAGS_DEBUG = -g
-- Configuring done
-- Generating done
-- Build files have been written to: /path/to/build
So on this compiler, CMAKE_CXX_FLAGS_DEBUG is set to -g. This is our baseline.
Experiment 2: Set-cache with force
Now we'll create a toolchain file called set-cache-force.cmake:
# set-cache-force.cmake
set(CMAKE_CXX_FLAGS_DEBUG "-DMY_DEBUG" CACHE STRING "C++ compiler flags" FORCE)
We'll configure the project with this toolchain:
$ rm -rf build
$ cmake -S . -B build --toolchain set-cache-force.cmake
...
-- CMAKE_CXX_FLAGS_DEBUG = -DMY_DEBUG
...
As we can see, the original -g flag was suppressed and the -DMY_DEBUG cache value "won". Of course, this isn't really a debug mode anymore, which should illustrate why overriding all the flags isn't always what we want.
Even worse, using FORCE here disables a user's ability to override CMAKE_CXX_FLAGS_DEBUG themselves:
$ rm -rf build
$ cmake -S . -B build --toolchain set-cache-force.cmake -DCMAKE_CXX_FLAGS_DEBUG="-DOVERRIDE"
...
-- CMAKE_CXX_FLAGS_DEBUG = -DMY_DEBUG
...
This is highly undesirable behavior. A user would need to edit your toolchain file to work around a bug or add further customizations.
Experiment 3: Set-cache without force
If we run the same experiment as before without FORCE setting it, then we still get the same flags, but we retain the ability to incrementally override the toolchain file.
# set-cache.cmake
set(CMAKE_CXX_FLAGS_DEBUG "-DMY_DEBUG" CACHE STRING "C++ compiler flags")
Now we can see that it works:
$ rm -rf build
$ cmake -S . -B build --toolchain set-cache.cmake
...
-- CMAKE_CXX_FLAGS_DEBUG = -DMY_DEBUG
...
And that it can still be overridden:
$ rm -rf build
$ cmake -S . -B build --toolchain set-cache.cmake -DCMAKE_CXX_FLAGS_DEBUG="-DOVERRIDE"
...
-- CMAKE_CXX_FLAGS_DEBUG = -DOVERRIDE
...
And it can even be overridden again:
$ cmake -S . -B build -DCMAKE_CXX_FLAGS_DEBUG="-DOVERRIDE2"
...
-- CMAKE_CXX_FLAGS_DEBUG = -DOVERRIDE2
...
Experiment 4: Set normal variable
Now we'll try to set this as a normal variable. Again, we'll create a toolchain file called set-normal.cmake:
# set-normal.cmake
set(CMAKE_CXX_FLAGS_DEBUG "-DMY_DEBUG")
Again, running this shows that -DMY_DEBUG "wins", overriding CMake's default flags:
$ cmake -S . -B build --toolchain set-normal.cmake
...
-- CMAKE_CXX_FLAGS_DEBUG = -DMY_DEBUG
...
Like experiment 2, this prevents users from overriding it... bad!
$ cmake -S . -B build --toolchain set-normal.cmake -DCMAKE_CXX_FLAGS_DEBUG="-DOVERRIDE"
...
-- CMAKE_CXX_FLAGS_DEBUG = -DMY_DEBUG
...
Experiment 5: Append normal variable
Now we'll try with the code in your post. Again, we'll use a toolchain called append-normal.cmake:
# append-normal.cmake
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DMY_DEBUG")
Now we get a very different result:
$ rm -rf build
$ cmake -S . -B build --toolchain append-normal.cmake
...
-- CMAKE_CXX_FLAGS_DEBUG = -DMY_DEBUG -DMY_DEBUG
...
This is just completely wrong! What happened here? Well, the toolchain file gets read multiple times during project initialization, and here this causes the -DMY_DEBUG flag to be appended twice. At least that's what happens on the first run:
$ cmake -S . -B build
...
-- CMAKE_CXX_FLAGS_DEBUG = -g -DMY_DEBUG
...
After the first run, the CMake default gets cached and so we append to that on subsequent runs. Furthermore, CMake only reads your toolchain file once now.
You must always make your toolchain files idempotent. That means that running it twice does the same thing as running it once.
Experiment 6: Using _INIT variables
This is the developer-intended way of doing things per the documentation. See the documentation here: https://cmake.org/cmake/help/latest/variable/CMAKE_LANG_FLAGS_INIT.html
Value used to initialize the CMAKE_<LANG>_FLAGS cache entry the first time a build tree is configured for language <LANG>. This variable is meant to be set by a toolchain file. CMake may prepend or append content to the value based on the environment and target platform.
Now we use a toolchain file called init-var.cmake:
# init-var.cmake
set(CMAKE_CXX_FLAGS_DEBUG_INIT "-DMY_DEBUG")
And we re-run the build:
$ rm -rf build
$ cmake -S . -B build --toolchain init-var.cmake
...
-- CMAKE_CXX_FLAGS_DEBUG = -DMY_DEBUG -g
...
Now we can see that CMake appended its default flags to the initial ones we provided. And indeed this still allows users to override things:
$ cmake -S . -B build --toolchain init-var.cmake -DCMAKE_CXX_FLAGS_DEBUG="-DOVERRIDE"
...
-- CMAKE_CXX_FLAGS_DEBUG = -DOVERRIDE
...
In my experience, 90%+ of the time it's correct to let CMake add in its extra flags using Experiment 6 (the _INIT variables). But every so often you'll want to completely override CMake using Experiment 3 (set(CACHE) without FORCE).
What you do not want to do is anything that behaves differently on subsequent runs (like experiment 5) or that disables key CMake functionality (ie. respecting the cache variable, like experiments 2 and 4).
When you use set(variable "value" CACHE STRING "..." FORCE), the variable is set for all the projects built in the current session (including those that are in the sub-directories).
But simply using set(variable "value") without the cache part only adds the flags for the immediate project scope (current CMakeLists.txt) and not the upper directories that have their own CMakeLists.txt.
How can I add the '/MT' flag from the command line using cmake?
Can I simply go cmake -D CMAKE_CXX_FLAGS="/MT" ..?
In the tutorials I've found online, I see people setting CMAKE_CXX_FLAGS_RELEASE and CMAKE_CXX_FLAGS_DEBUG separately and haven't seen any examples with setting it from the command line.
Did some testing, it did not work with cmake -D CMAKE_CXX_FLAGS="/MT" .. but worked with cmake -D CMAKE_CXX_FLAGS_RELEASE="/MT" ..
I verified the resulting library using dumpbin.
I am trying to build gcc 4.7.2 using a custom prefix $PREFIX
I have built and installed all the prerequisites into my prefix location, and then successfully configured, built and installed gcc.
The problem that I now have is that $PREFIX is not in the library search path, and therefore the shared libraries cannot be found.
$PREFIX/bin $ ./g++ ~/main.cpp
$PREFIX/libexec/gcc/x86_64-suse-linux/4.7.2/cc1plus: \
error while loading shared libraries: \
libcloog-isl.so.1: \
cannot open shared object file: No such file or directory
What works, but isn't ideal
If I export LD_LIBRARY_PATH=$PREFIX/lib then it works, but I'm looking for something which works without having to set environment variables.
If I use patchelf to set the RPATH on all the gcc binaries then it also works; however this involves searching out all elf binaries and iterating over them calling patchelf, I would rather have something more permanent.
What I think would be ideal for my purposes
So I'm hoping there is a way to have -Wl,-rpath,$PREFIX/lib passed to make during the build process.
Since I know the paths won't need to be changed this seems like the most robust solution, and can be also be used for when we build the next gcc version.
Is configuring the build process to hard code the RPATH possible?
What I have tried, but doesn't work
Setting LDFLAGS_FOR_TARGET prior to calling configure:
All of these fail:
export LDFLAGS_FOR_TARGET="-L$PREFIX/lib -R$PREFIX/lib"
export LDFLAGS_FOR_TARGET="-L$PREFIX/lib"
export LDFLAGS_FOR_TARGET="-L$PREFIX/lib -Wl,-rpath,$PREFIX/lib"
Setting LDFLAGS prior to calling configure:
export LDFLAGS="-L$PREFIX/lib -Wl,-rpath,$PREFIX/lib"
In any event I worry that these will override any of the LDFLAGS gcc would have had, so I'm not sure these are a viable option even if they could be made to work?
My configure line
For completeness here is the line I pass to configure:
./configure \
--prefix=$PREFIX \
--build=x86_64-suse-linux \
--with-pkgversion='SIG build 12/10/2012' \
--disable-multilib \
--enable-cloog-backend=isl \
--with-mpc=$PREFIX \
--with-mpfr=$PREFIX \
--with-gmp=$PREFIX \
--with-cloog=$PREFIX \
--with-ppl=$PREFIX \
--with-gxx-include-dir=$PREFIX/include/c++/4.7.2
I've found that copying the source directories for gmp, mpfr, mpc, isl, cloog, etc. into the top level gcc source directory (or using symbolic links with the same name) works everywhere. This is in fact the preferred way.
You need to copy (or link) to those source directory names without the version numbers for this to work.
The compilers do not need LD_LIBRARY_PATH (although running applications built with the compilers will need an LD_LIBRARY_PATH to the $PREFIX/lib64 or something like that - but that's different)
Start in a source directory where you'll keep all your sources.
In this source directory you have your gcc directory either by unpacking a tarball or svn...
I use subversion.
Also in this top level directory you have, say, the following source tarballs:
gmp-5.1.0.tar.bz2
mpfr-3.1.1.tar.bz2
mpc-1.0.1.tar.gz
isl-0.11.1.tar.bz2
cloog-0.18.0.tar.gz
I just download these and update to the latest tarballs periodically.
In script form:
# Either:
svn checkout svn://gcc.gnu.org/svn/gcc/trunk gcc_work
# Or:
bunzip -c gcc-4.8.0.tar.bz2 | tar -xvf -
mv gcc-4.8.0 gcc_work
# Uncompress sources.. (This will produce version numbered directories).
bunzip -c gmp-5.1.0.tar.bz2 | tar -xvf -
bunzip -c mpfr-3.1.1.tar.bz2 | tar -xvf -
gunzip -c mpc-1.0.1.tar.gz | tar -xvf -
bunzip -c isl-0.11.1.tar.bz2 | tar -xvf -
gunzip -c cloog-0.18.0.tar.gz | tar -xvf -
# Link outside source directories into the top level gcc directory.
cd gcc_work
ln -s ../gmp-5.1.0 gmp
ln -s ../mpfr-3.1.1 mpfr
ln -s ../mpc-1.0.1 mpc
ln -s ../isl-0.11.1 isl
ln -s ../cloog-0.18.0 cloog
# Get out of the gcc working directory and create a build directory. I call mine obj_work.
# I configure the gcc binary and other outputs to be bin_work in the top level directory. Your choice. But I have this:
# home/ed/projects
# home/ed/projects/gcc_work
# home/ed/projects/obj_work
# home/ed/projects/bin_work
# home/ed/projects/gmp-5.1.0
# home/ed/projects/mpfr-3.1.1
# home/ed/projects/mpc-1.0.1
# home/ed/projects/isl-0.11.1
# home/ed/projects/cloog-0.18.0
mkdir obj_work
cd obj_work
../gcc_work/configure --prefix=../bin_work <other options>
# Your <other options> shouldn't need to involve anything about gmp, mpfr, mpc, isl, cloog.
# The gcc build system will find the directories you linked,
# then configure and compile the needed libraries with the necessary flags and such.
# Good luck.
I've been using this configure option with gcc-4.8.0, on FreeBSD, after building and installing gmp, isl and cloog:
LD_LIBRARY_PATH=/path/to/isl/lib ./configure (lots of other options) \
--with-stage1-ldflags="-rpath /path/to/isl/lib -rpath /path/to/cloog/lib -rpath /path/to/gmp/lib"
and the resulting gcc binary does not need any LD_LIBRARY_PATH. The LD_LIBRARY_PATH for configure is needed because it compiles a test program to check for the ISL version, which would fail if it didn't find the ISL shared lib.
I tried it on Linux (Ubuntu) where it failed during configuring because the -rpath args were passed to gcc instead of ld. I could fix this by using
--with-stage1-ldflags="-Wl,-rpath,/path/to/isl/lib,-rpath,/path/to/cloog/lib,-rpath,/path/to/gmp/lib"
instead.
Just using configure --with-stage1-ldflags="-Wl,-rpath,/path/to/lib" was not enough for me to build gcc 4.9.2, bootstrap failed in stage 2. What works is to pass he flags directly to make via
make BOOT_LDFLAGS="-Wl,-rpath,/path/to/lib"
I got this from https://gcc.gnu.org/ml/gcc/2008-09/msg00214.html
While it still involves setting environment variables, what I do is that I define LD_RUN_PATH, which sets the rpath. That way the rest of the system can keep using the system provided libraries instead of using the ones that your gcc build generates.
I am going to make a suggestion that I believe solves your problem, although it definitely does not answer your question. Let's see how many downvotes I get.
Writing a generic wrapper script to set LD_LIBRARY_PATH and then to run the executable is easy; see https://stackoverflow.com/a/7101577/768469.
The idea is to pass something like --prefix=$PREFIX/install to configure, building an install tree that looks like this:
$PREFIX/
install/
lib/
libcloogXX.so
libgmpYY.so
...
bin/
gcc
emacs
...
bin/
.wrapper
gcc -> .wrapper
emacs -> .wrapper
.wrapper is a simple shell script:
#!/bin/sh
here="${0%/*}" # or use $(dirname "$0")
base="${0##*/}" # or use $(basename "$0")
libdir="$here"/../install/lib
if [ "$LD_LIBRARY_PATH"x = x ] ; then
LD_LIBRARY_PATH="$libdir"
else
LD_LIBRARY_PATH="$libdir":"$LD_LIBRARY_PATH"
fi
export LD_LIBRARY_PATH
exec "$here"/../install/bin/"$base" "$#"
This will forward all arguments correctly, handle spaces in arguments or directory names, and so forth. For practical purposes, it is indistinguishable from setting the rpath like you want.
Also, you can use this approach not only for gcc, but for your entire my-personal-$PREFIX tree. I do this all the time in environments where I want an up-to-date suite of GNU tools, but I do not have (or want to admit to have) root access.
Try to add your $PREFIX to /etc/ld.so.conf and then run ldconfig:
# echo $PREFIX >> /etc/ld.so.conf
# ldconfig
This will recreate cache that is used by runtime linker and it will pick up your libraries.
WARNING: This operation will cause ALL applications to use your newly compiled libraries in $PREFIX instead of default location
I'm getting this error:
OpenCV-2.4.3/modules/features2d/src/freak.cpp:437: error: unable to
find a register to spill in class 'GENERAL_REGS'
After doing:
tar xfj OpenCV-2.4.3.tar.bz2
cd OpenCV-2.4.3
mkdir release
cd release
cmake -D CMAKE_BUILD_TYPE=RELEASE -D CMAKE_INSTALL_PREFIX=/usr/local -D BUILD_NEW_PYTHON_SUPPORT=ON -D BUILD_EXAMPLES=ON ..
make
The same procedure works on another machine. Any ideas?
You need to dig into the Makefiles to remove -O for freak.cpp.
UPDATE:
This is exactly how one should do it (tested with 2.4.3 and 2.4.4).
you need to edit
YOUR_BUILD_DIR/modules/features2d/CMakeFiles/opencv_features2d.dir/build.make
Search for freak.cpp. You find three blocks: Building CXX..., Preprocessing CXX..., and Compiling CX.... I just needed to change the Building part. The last line of that block looks like this:
.... YOUR_COMPILER $(CXX_DEFINES) $(CXX_FLAGS) ...
and if you check you find out that CXX_FLAGS has a -O3 in it. If you add -O0 after CXX_FLAGS it suppresses the O3. So your lines should look like this.
.... YOUR_COMPILER $(CXX_DEFINES) $(CXX_FLAGS) -O0 ...
This is at least working here!
I struggled with this for quite a few hours as well on my CentOS 5.x boxen, and here's my solution.
It's apparent you need to update 'gcc' but natively upgrading via RPM or just grabbing RPM's at random causing some serious config mgmt issues on your server. I don't have time to compile gcc/g++ via source right now either. After grazing out in the repo for a while, I found that there is, indeed, an 4.x release of gcc in the base repo.
Do this (or someone with 'root' to do it in case of OP who doesn't have access):
# yum install gcc44 gcc44-c++ -y
...CentOS/RHEL have bundled a preview RPM of gcc-4.4.6.
Then when you go to do 'cmake' to build your release environment, do at least the following (your cmake params may vary):
# cd /path/to/OpenCV-2.4.3
# mkdir release && cd release
# env CC=/usr/bin/gcc44 CXX=/usr/bin/g++44 cmake -D CMAKE_BUILD_TYPE=RELEASE -D CMAKE_INSTALL_PREFIX=/place/to/install/ -D BUILD_PYTHON_SUPPORT=ON /path/to/OpenCV-2.4.3/
That will give you a successful build of OpenCV-2.4.3 natively with CenOS/RHEL 5.x.
Had the same problem and solved it like wisehippy with one slight change:
# yum install gcc44 gcc44-c++ -y
# mkdir release && cd release
# cmake -D CMAKE_BUILD_TYPE=RELEASE -DCMAKE_CXX_COMPILER=/usr/bin/g++44 -DCMAKE_C_COMPILER=/usr/bin/gcc44 <OpenCV_Dir>
I found the problem to be solved once I updated my c++ to point to g++44, instead of the default g++ which was 4.1.
As root verify that the files are the same before doing this step, it may not be necessary for you.
diff /usr/bin/c++ /usr/bin/g++
There should be nothing returned if the files are the same. If this is the case, continue.
Backup your old file. You can delete the file as well because it's the same as g++, but I like to be careful.
mv /usr/bin/c++ /usr/bin/c++4.1
Create a link so that C++ points to your g++44. You could use symbolic link here as well.
ln /usr/bin/g++44 /usr/bin/c++
Done.