Merging make and cmake's make into build system - c++

I have to merge cmake's makes and makes in our build systems. The build systems are supposed to be able to work with both options make and cmake. The problem is that cmake's make exports do not contain all variables and settings, which need to be set as make in our build systems. Basically, we use three complicated build systems for cross platform development and I do not like setting everything on many places, because then it is hard to maintain the system like that.
E g. makefiles from many coders in all build system contains include common file like:
include $(PROJECT_CONF_DIR)/common/something.mk
How to solute it by cmake? I do not like modifying coders' CMakeLists.txt (max. one row solution for them) and I also do not like modifying cmake exports into make files.
Basically, I need to put somewhere in cmake command or cmake's export (the best) some link which will lead to include all 'garbage' expecting by our build tool chains.
Make sure that CMakeLists.txt can contain many cmake subprojects and libraries.
e.g. Our build system from makefiles contains something like:
directories-default:
mkdir -p $(BUILD_DIR)
mkdir -p $(OBJ_DIR)
I need to implement it somehow in cmake include.

To be able to run make directories-default after configuration, you have to create a target. You can make a target that will call a custom command, which would run the shell commands you need.
add_custom_target(directories-default COMMAND mkdir -p "dir1" COMMAND mkdir -p "dir2")
The syntax above will result in a target that is always considered out of date, ie every time you run make directories-default (or make all), the commands will be executed. If you don't want to re-run the command every time you can use a custom command:
add_custom_command(OUTPUT "dir3" "dir4" COMMAND mkdir -p "dir3" COMMAND mkdir -p "dir4")
add_custom_target(directories-default2 DEPENDS "dir3" "dir4")
Here make directories-default2 will only run the commands the first time you run it. You can also create a dependency chain of commands using the DEPENDS argument in add_custom_command.

Related

How to execute CMake custom command without building any target?

I have a CMakeLists.txt file with add_custom_command that adds a command to unite all the project source files and generate one output unit.cc file. Is there a way to just run this command without building any target that depends on it? Like cmake -E ... does. I need to sloc the file and don't wanna wait the long compilation.
I tried to look at the docs but they said, IIUC, that I can run commands only when they depend on some target.

CMake: compilation speed when including external makefile

I have a c++ cmake project. In this project I build (among other) one example, where I need to use another project, call it Foo. This Foo project does not offer a cmake build system. Instead, it has a pre-made Makefile.custom.in. In order to build an executable that uses Foo's features, one needs to copy this makefile in his project, and modify it (typically setting the SOURCES variable and a few compiler flags). Basically, this Makefile ends up having the sources for your executable and also all the source files for the Foo project. You will not end up using Foo as a library.
Now, this is a design I don't like, but for the sake of the question, let's say we stick with it.
To create my example inside my cmake build I added a custom target:
CONFIGURE_FILE( ${CMAKE_CURRENT_SOURCE_DIR}/Makefile.custom.in Makefile.custom)
ADD_CUSTOM_TARGET(my_target COMMAND $(MAKE) -f Makefile.custom
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
This works. I can specify some variables to cmake, which get resolved in the call to CONFIGURE_FILE, and I end up with a working Makefile.custom. Then, invoking make my_target from the build directory, I can build the executable. I can even add it to the all target (to save me the effort of typing make my_target) with
SET_TARGET_PROPERTIES(my_target PROPERTIES EXCLUDE_FROM_ALL FALSE)
Sweet. However, cmake appears to assign a single job to the custom target, slowing down my compilation time (the Foo source folder contains a couple dozens cpp files). On top of that, the make clean target does not forward to the custom makefile. I end up having to add another target:
ADD_CUSTOM_TARGET(really-clean COMMAND "$(MAKE)" clean
COMMAND "$(MAKE)" -f Makefile.custom clean
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
which, unlike my_target with all, I can't include in the clean target (can I?).
Now, I know that a cleaner solution would be to have the Foo project be built as an external project, and then link to it. However, I've been 'recommended' to use their Makefile.custom.in makefile, modifying the few lines I need (adding my sources, specifying compiler flags, and few other minor modifications). So, regardless of how neat and clean this design pattern is, my questions are:
is there a way to tell cmake that make should use more than 1 job when making the target my_target?
is there a cleaner way to include a pre-existing makefile in a cmake project? Note that I don't want (can't?) use Foo as a library (and link against it). I want (need?) to compile it together with my executable using a makefile not generated by cmake (well, cmake can help a bit, through CONFIGURE_FILE, by resolving some variables, but that's it).
Note: I am aware of ExternalProject (as suggested also in this answer), but I think it's not exactly what I need here (since it would build Foo and then use it as a library). Also, both my project and Foo are written exclusively in C++ (not sure this matter at all).
I hope the question makes sense (regardless of how ugly/annoying/unsatisfactory the resulting design would be).
Edit: I am using cmake version 3.5.2
First, since you define your own target, you can assign more cores to the build process for the target my_target, directly inside your CMakeLists.txt.
You can include the Cmake module ProcessCount to determine the number of cores in your machine and then use this for a parallel build.
include(ProcessorCount)
ProcessorCount(N)
if(NOT N EQUAL 0)
# given that cores != 0 you could modify
# math(EXPR N "${N}+1") # modify (increment/decrement) N at your will, in this case, just incrementing N by one
set(JOBS_IN_PARALLEL -j${N})
endif(NOT N EQUAL 0)
and when you define your custom target have something like the following:
ADD_CUSTOM_TARGET(my_target
COMMAND ${CMAKE_MAKE_PROGRAM} ${JOBS_IN_PARALLEL} -f Makefile.custom
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
by the way, I don't think there's the need for you to include also CMAKE_BUILD_TOOL among the COMMANDs in your target.
I believe that instead of modifying the lines as above, you could call
make -j8 my_target
and it might start 8 jobs (just an example) without modifying the CMakeLists.txt, but I cannot guarantee this works having defined the COMMAND the way you have, just try if that's enough.
For the second point, I cannot think right now of a "cleaner" way.

Enable cmake options/flag after making the file

I don't have much knowledge about cmake. I installed a package libfreenect2 following the instructions on their github page. The instructions were as follows-
Clone the repository. And follow the cmake step:
cd ..
mkdir build && cd build
cmake .. -DCMAKE_INSTALL_PREFIX=$HOME/freenect2
make
make install
However, after installing I realised the program/package that required libfreenect2 as a dependency required me to use:
cmake .. -DCMAKE_INSTALL_PREFIX=$HOME/freenect2 -DENABLE_CXX11=ON
You may have noticed, it required me to use an extra flag -DENABLE_CXX11=ON. How can I fix this? How can I set ENABLE_CXX11=ON after the whole make process has been completed? By the way what does -D do? (are these -DXXX things called options or flag)
In case your answer is to repeat the whole process again then kindly guide me through the step by step process of deleting the correct files. I don't want to delete other dependencies.
Here are some other stackoverflow answers relating to cmake-
set cmake option(), cmake option to include a directory, What does cmake do
SOLUTION - I used the accepted solution to enable the flag. Even though it worked for my problem (libfreenect2) still it will be amazing if someone could provide an answer which doesn't involve reinstalling.
My warm suggestion would be to repeat the process with that option ON.
First you should delete what was previously generated.
The sequence of commands to follow is the following:
rm -rf build
rm -rf $HOME/freenect2
just to be entirely sure you start from a "clean state".
I don't see the need to do rm -rf $HOME/freenect2 as that files/dir will be overwritten by the new install, but shouldn't hurt.
You can also try the suggestion in the SO post mentioned in one of the comments.
Then repeat the process from the root dir of libfreenect2:
mkdir build && cd build
cmake .. -DCMAKE_INSTALL_PREFIX=$HOME/freenect2 -DENABLE_CXX11=ON
make
make install
Alternatively, if you're entirely sure that you will build libfreenect2 always with that option ENABLE_CXX11=ON, you could explicitely set it ON once and for all in the CMakeLists.txt of libfreenect2, specifically changing the line:
OPTION(ENABLE_CXX11 "Enable C++11 support" OFF)
into
OPTION(ENABLE_CXX11 "Enable C++11 support" ON)
In this last case, you will just need to do
mkdir build && cd build
cmake .. -DCMAKE_INSTALL_PREFIX=$HOME/freenect2
make
make install
of course after you've cleaned as explained at the beginning.
About -D for CMake, it allows you to pass options. Directly from the documentation:
-D <var>:<type>=<value>
Create a cmake cache entry.
When cmake is first run in an empty build tree, it creates a
CMakeCache.txt file and populates it with customizable settings for
the project. This option may be used to specify a setting that takes
priority over the project’s default value. The option may be repeated
for as many cache entries as desired.
So if there's some project default options that one wants to change/overwrite than it can be done with this.

Separate build directory for autotools projects not designed to use one

... Sorry, this has to be a duplicate, but I'm just running across answers for people who are making their own projects and can change the build system setup.
Can I always compile a program in a separate build directory, or must it be supported by the program's build system?
For vim, you compile using: "./configure && make && sudo make install". If I'm in vim.hg.build and run "../vim.hg/configure .....", I get :
../vim.hg/configure: line 6: cd: src: No such file or directory
For git, you compile using: "make configure && ./configure && make && sudo make install". I was hoping being in git.git.build and running "make --directory=../git.git configure" would work, but that leaves the configure file in ../git.git. Well, maybe just configure left behind isn't so bad, so I then tried "../git.git/configure" which successfully created config.status, config.log, and config.mak.autogen in the build directory. But running make gives:
make: *** No targets specified and no makefile found. Stop.
... Yes, the only Makefile is in git.git itself.
I even tried symlinking the entire directory by running:
for fl in `ls -a ../vim.hg`; do
echo "$fl"
ln -s ../vim.hg/$fl $fl
done
... But, vim's configure and make only modify existing files and subdirectories, so even though I can build this way, the build directory is left with nothing more than symlinks -- no actual separation.
Go cmake!
Out-of-tree building is a feature of Autotools that requires both Autoconf and Automake.
Vim and Git both only use Autoconf and not Automake, so they can't take advantage of that feature.
As a more general answer to your question: simple Autotools projects should work with out-of-tree builds automatically. When using certain advanced features, a bit of care must be taken to ensure that out-of-tree builds continue to work. Sometimes projects don't do this.
(Running make distcheck will test out-of-tree building, so it's a good idea to run it at least once before making a release.)

Cmake generate independent makefiles

We are moving from MPC to CMake.
We provide a lib with some samples. The samples are coming with makefiles.
The problem is that the makefiles, generated by cmake contains absolute paths but not relative ones:
# The main all target
all: cmake_check_build_system
cd /.../Projects/cpp_trunk && $(CMAKE_COMMAND) -E cmake_progress_start /.../Projects/cpp_trunk/CMakeFiles /.../Projects/cpp_trunk/samples/CMakeFiles/progress.make
cd /.../Projects/cpp_trunk && $(MAKE) -f CMakeFiles/Makefile2 samples/all
$(CMAKE_COMMAND) -E cmake_progress_start /.../cpp_trunk/CMakeFiles 0
So, when it is copied it's become broken.
It there any way to work it around?
UPD: I have read the FAQ, but my question is still taking place, perhaps somebody managed to get around?
What I've done to get around this sort of thing is write a small wrapper Makefile around cmake. I put the Makefile at the project root, with contents like this:
all: cmake
cmake:
[ -f build/CMakeCache.txt ] && [ "$$(pwd)" != "$$(grep 'CMAKE_HOME_DIRECTORY:INTERNAL' build/CMakeCache.txt | cut -d '=' -f 2)" ] \
&& rm -rf build || true
mkdir -p build && cd build && cmake ..
make -C build
clean:
rm -rf build
There's probably a cleaner way to do it, but it works for me:
make # build in one directory
cd ..
olddir=$(basename $OLDPWD) && rsync -ravz $olddir ${olddir}-test && cd ${olddir}-test # copy to another directory
make # running make in the new dir triggers a full rebuild
make # running make a second time in the new dir does not rebuild
The makefiles created by CMake are not part of your source code base. The CMakeLists.txt files that you use as input to CMake are part of your source code base. When you copy your source code to a different place and want to build it there, build from your source code. That means re-running CMake. (And that's your workaround.)
I've been using CMake for over ten years continuously on one project. One of the handy tricks my team has learned is that you can have multiple copies of one part of your source code base on one development host that all share the same copy of the rest of your source code base. Try doing that with relative paths! We rely on the fact that every time we build source code in a new build directory, CMake will figure out the correct paths to all the source files, which are not necessarily the same relative to the new build directory as they were in the previous build.
The build files that are generated by cmake (makefiles, ninja files, etc), are going to have hardcoded paths and other not-portable stuff in them. That's ok. Treat them as temporary files that are part of the build process. You will only version the CMakeLists.txt files, and then generate new makefiles (or whatever) on other machines or in other directories when you check it out. You can even have different people on the team using different build files - one person using makefiles, one person using eclipse+ninja, etc, all generated by cmake.