CMake build multiple targets in different build directories - c++

I have the following CMake structure:
CMakelists.txt
toolchain.cmake
folder1
----CMakelists.txt
folder2
----CMakelists.txt
etc..
My first-level CMakelists.txt file includes the other subdirectories. Now I want to build my code for a different target.
The manual way is:
1.
mkdir hostBuild
cd hostBuild
cmake ..
make
2.
mkdir crossBuild
cd crossBuild
cmake .. --DCMAKE_TOOLCHAIN_FILE=toolchain.cmake
make
Is it possible that this process can run automatically?
For example, I just have to run cmake . at my first level.
Is something like this is possible?

No. The recommendation would be to just put your manual steps into a shell script.
CMake can only handle one compiler/make environment at a time (if you switch the compiler you need a different binary output directory).
Especially a toolchain file that does contain SET(CMAKE_SYSTEM_NAME ...) does change the whole outcome of the configuration/generation process.
For details on what CMake does see: CMake: In which Order are Files parsed (Cache, Toolchain, …)?
And you could make use of some CMake command line options in your shell script:
if [ ! -d hostBuild ]; then
cmake -E make_directory hostBuild
cmake -E chdir hostBuild cmake ..
fi
cmake --build hostBuild
...

Related

Cmake: Specify a separate build toolchain for testing?

I am using CMake to build a project for an embedded system, but my unit testing is done on an x86 host. Therefore, I need to use a completely different compiler to build the tests from the one used for the cross-compiled binary.
I have a main CMakeLists.txt file at the top level of my project, and then another one in my testing folder which gets added with add_subdirectory at the top level. Should I just keep them completely separate or is there a better way to accomplish this?
Running my main build without the cross compiler will cause it to fail, so it really needs to be a separate process for the tests.
Should I just keep them completely separate
There's no need to. Keep proper minimum dependencies between targets, add EXCLUDE_FROM_ALL to tests targets and manage targets with good grouping. Or explicitly compile only targets that you want to compile.
or is there a better way to accomplish this?
The known limitation:
You may have one compiler per one cmake configuration.
You can't (easily ;) "switch" between compilers and use different compiler for different target.
To use a different compiler, you have to reconfigure cmake.
Solution:
Configure cmake differently for unit testing and for normal compilation.
Typically use an external tool/script/whatever to manage cmake configuration and execute actions you want.
By properly labeling unit tests and using EXCLUDE_FROM_ALL on unused target, compile only what you want.
I typically use a Makefile, only because shell does autodetection of autocompletion for me:
all: normal_build
normal_build:
cmake -S . -B _build/$# \
-DCMAKE_TOOLCHAIN_FILE=the_target_toolchain_file.camle
cmake --build _build/$# --target the_firmware
unit_tests_on_pc:
camke -S . -B _build/$# \
-DCMAKE_C_FLAGS="-fsanitize -Wall -Wextra -pedantic etc...."
cmake --build _build/$# --target unit_tests # note - compile only unit tests
cd _build/$# && ctest -LE "on_target"
# tests with set CMAKE_CROSSCOMPILING_EMULATOR in toolchain file
unit_tests_on_simulator:
cmake -S . -B _build/$# \
-DCMAKE_TOOLCHAIN_FILE=the_toolchain_file_for_simulator.camke
cmake --build _build/$# --target unit_tests
cd _build/$# && ctest -E "on_target"
# tests with set CMAKE_CROSSCOMPILING_EMULATOR to a script
# that flashes some connected target with the firmware and get's output from it
unit_tests_on_target:
cmake -S . -B _build/$# \
-DCMAKE_TOOLCHAIN_FILE=the_toolchain_file_for_unit_tests.camke
# special targets compiled here - only integration tests for real hardware!
cmake --build _build/$# --target integration_tests
cd _build/$# && ctest -E "on_target"
# etc..

How can I convert a configure script to a CMakeLists file?

I'm wanting to use this library in my cmake project, however it comes with a configure file instead of CMakeLists.txt
#! /bin/sh
# waf configure wrapper
# based on http://code.google.com/p/waf/source/browse/configure
CUR_DIR=$PWD
#possible relative path
WORKINGDIR=`dirname $0`
cd $WORKINGDIR
#abs path
WORKINGDIR=`pwd`
cd $CUR_DIR
WAF=$WORKINGDIR/tools/waf
# Generates a Makefile. Requires that $WAF is set.
#
generateMakefile()
{
cat > Makefile << EOF
#!/usr/bin/make -f
# Waf Makefile wrapper
WAF_HOME=$CUR_DIR
all:
#$WAF build
all-debug:
#$WAF -v build
all-progress:
#$WAF -p build
install:
$WAF install --yes;
uninstall:
$WAF uninstall
clean:
#$WAF clean
distclean:
#$WAF distclean
#-rm -rf build
#-rm -f Makefile
check:
#$WAF check
dist:
#$WAF dist
.PHONY: clean dist distclean check uninstall install all
EOF
}
generateMakefile
"${WAF}" configure $*
exit $?
Are there automated tools for the conversion? Does CMake supoprt the use of configure files? Is there a rule of thumb for conversion - i.e. replace ... with add_library?
You don't need to convert an upstream library to cmake to be able to use it in cmake projects. As long as you're able to install and/or link to that library, you can configure your cmake project to use it.
A common pattern to consume third-party libraries with cmake is to use cmake's find_package() function by supplying your own special-purpose cmake module files to find and configure the library.
Say, you're hoping to load libfoo. Here are the steps:
create a directory within your project tree to store your custom cmake modules (say, ./cmake/modules)
in that directory create a text file named FindFoo.cmake.
Within FindFoo.cmake add checks to determine if foo is actually present in the system. If it is then set the relevant variables. Otherwise, throw an error. The ideal thing is to create a build target for that library, which you can simply add as dependencies to other cmake targets.
Configure your cmake project to use your local modules by adding set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/modules/"),
Finally, configure your cmake project to include your Foo library by calling find_package(Foo REQUIRED).
The way to do the conversion is to read the configure script and understand what it does and how/why. Then write a CMakeLists.txt file that achieves the same.
There are no shortcuts.

Using cmake on windows without IDE

this might be a duplicate, but I've already spent a couple of hours searching for an answer... without solution. First of all I know this problem might not exist if I'd use a Linux, but I am on Windows.
I am pretty new to c++ but already got some experience with java and gradle. I try to use cmake just like I am used to use gradle. I already read the cmake wiki, but I either do not find the correct pages or I just don't understand it. Here is my directory structure:
MyProject
-bin
-include
--header1.h
--header2.h
--header3.h
--header4.h
--header5.h
--header6.h
-src
--CMakeLists.txt
--MyProjectConfig.h.in
--impl1.cpp
--impl2.cpp
--impl3.cpp
--impl4.cpp
--impl5.cpp
--impl6.cpp
-main.cpp
-CMakeLists.txt
My CMakeLists.txt in my project folder looks like:
cmake_minimum_required (VERSION 3.14)
project (MyProject)
add_subdirectory(src)
file(GLOB_RECURSE sources src/*.cpp include/*.h)
# The version number.
set (Tutorial_VERSION_MAJOR 0)
set (Tutorial_VERSION_MINOR 1)
# configure a header file to pass some of the CMake settings
# to the source code
configure_file (
"${PROJECT_SOURCE_DIR}/MyProjectConfig.h.in"
"${PROJECT_BINARY_DIR}/MyProjectConfig.h"
)
# add the binary tree to the search path for include files
# so that we will find MyProjectConfig.h
include_directories("${PROJECT_BINARY_DIR}")
install (FILES "${PROJECT_BINARY_DIR}/MyProjectConfig.h"
DESTINATION include)
add_executable(MyProject main.cxx ${sources})
# add the install targets
install (TARGETS MyProject DESTINATION bin)
My CMakeLists.txt in the src folder looks like:
cmake_minimum_required (VERSION 3.14)
include_directories(${MyProject_SOURCE_DIR}/MyProject/include)
I use the command in the bin bin directory: cmake -G "MinGW Makefiles" -S ../src
I got 2 questions now:
(How do I tell cmake to always use MinGW? ( I don't want to use -G always)) solved
(The compiled file build\CMakeFiles\3.14.0-rc2\CompilerIdCXX\a.exe does not have the expected behavior. It should print "Hello world!" and "My Class", while "My Class" is printed from the attribute of a class created from impl1.cpp, however it does nothing.) needs clarification:
How do I build a windows .exe-file to ruin on the console?
Edit:
I have learned that I have to call cmake --build . in my bin directory after creating the cmake files. However I just don't get an exe-file. With flag -v I get this output:
"C:\Program Files\CMake\bin\cmake.exe" -SD:\git\MyProject\src -BD:\git\MyProject\bin --check-build-system CMakeFiles\Makefile.cmake 0
"C:\Program Files\CMake\bin\cmake.exe" -E cmake_progress_start D:\git\MyProject\bin\CMakeFiles D:\git\MyProject\bin\CMakeFiles\progress.marks
C:/MinGW/bin/mingw32-make.exe -f CMakeFiles\Makefile2 all
mingw32-make.exe[1]: Entering directory 'D:/git/MyProject/bin'
mingw32-make.exe[1]: Nothing to be done for 'all'.
mingw32-make.exe[1]: Leaving directory 'D:/git/MyProject/bin'
"C:\Program Files\CMake\bin\cmake.exe" -E cmake_progress_start D:\git\MyProject\bin\CMakeFiles 0 ```
Using the -G option is the standard way of doing it. It prevents you from having to put system-specific settings into your CMake config (like the hardcoded paths to MingW) and lets you use other compilers without having to change build scripts.
The a.exe you started is not your build output. It should be called MyProjectExec.exe. Also, you need to specify all source files in your call to add_executable. add_subdirectory does not automatically add any source files (to what build output should it add them?), it just executes the CMakeLists.txt.

cmake build executable with relative paths for dependencies (relocatable executable)

I have a package that is using cmake as its compiler. If I install the dependencies it needs first using a package manager then run cmake e.g.
$ sompackage-manager install depend1 depend2
$ wget http://a.b.c/somepackage.tgz
$ tar -xf somepackage.tgz
$ cd somepackage/
$ ls
CI CMakeFiles CONTRIBUTING.md README.md
CMakeCache.txt CMakeLists.txt doc LICENSE
cmake .
This will work fine. cmake finds all the dependencies and the project will create a folder in the build directory named bin that the executable will be in. I can then move the executable where ever id like. I assume the executable either knows the full path of the dependencies or has a list of full paths to check.
What id like to do is this:
create a folder like $HOME/newpackage. Then install the dependencies (the dependencies happens to use a configure script) to that directory e.g.
$ mkdir $HOME/newpackage/depend1
$ wget http://a.b.c/depnd1.tgz
$ tar -xf depend1.tgz
$ cd depend1
$ ./configure --prefix=$HOME/newpackage/depend1
Once all the dependencies are installed to $HOME/newpackage/depend1
Id then like to go back to the somepackage build directory and tell cmake to build the package to $HOME/newpackage/ dir but also to look for the dependencies relative to where the executable is i.e a path like ./. The end result would allow me to move the newpackage directory with the executable and the dependencies folders without breaking any paths.
I am having trouble finding the right cmake options or wether or not they are available.
Is this possible with cmake and what is the best way to go forward?

CMake compile -s -mt version of rabbitmq-c

I run cmake in command prompt with:
mkdir build && cd build
.. cmake
But now, I have problem constructing the command to build realease static.
I tried:
C:\Users\Kuba\Downloads\rabbitmq-c>cmake --build build --BUILD_STATIC_LIBS=ON
Which yields the error:
Unknown argument --BUILD_STATIC_LIBS=ON
How to correct this? Thanks !
You should define the variable using the -D option:
cmake --build build -DBUILD_STATIC_LIBS=ON
Please read the documentation for more information.
Configuring the build is a separate step from building it.
From the source directory create a binary directory:
mkdir build && cd build
Then configure the build (this is where you can add other build-flags):
cmake -DBUILD_STATIC_LIBS=ON ..
then build it:
cmake --build .