How to configure external cmake libraries? - cmake

What I wanted to do is call
add_subdirectory(ext/oglplus)
and be done with it. Unfortunately it is not that simple. There is a huge buildscript which detects various opengl settings. So I tried the following
ExternalProject_Add(liboglplus
SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/ext/oglplus
CONFIGURE_COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/ext/oglplus/configure.py --use-glew
BUILD_COMMAND ${MAKE})
The problem that I have is don't really want to build it like that. It also doesn't build correctly because for some reason it wants to install the library and because there is no install target it will abort the compilation.
But the build script is calling cmake under the hood.
So what I want to do is to tell cmake to use "cofigure.py" instead of "cmake .." and then use it like any other cmake library.
Is this possible?

I used to call Linux Kernel KBuild from CMake using
ADD_CUSTOM_COMMAND() and ADD_CUSTOM_TARGET()
This way you can run arbitrary commands (like your config.py) and use the output.
First setup the command with all command-line options as CMake-variables, in tou case this would be calling the config.py script ${CMAKE_CURRENT_SOURCE_DIR}/ext/oglplus/.
Instead of encoding the Path to your script in the command (adding ext/oglplus) I think it may be better adding WORKING_DIRECTORY to the custom command:
add_custom_command
SET(KBUILD_CMD ${CMAKE_MAKE_PROGRAM}
-C ${KERNEL_BUILD_DIR}
CROSS_COMPILE=${CROSS_COMPILE} ARCH=${ARCH}
EXTRA_CFLAGS=${KBUILD_EXTRA_CFLAGS}
INSTALL_MOD_PATH=${INSTALL_MOD_PATH}
M=${CMAKE_CURRENT_SOURCE_DIR}
KBUILD_EXTRA_SYMBOLS=${depends_module_ksyms}
)
Add a custom command that calls your build-script and creates a file in the CMAKE_CURRENT_BINARY_DIRECTORY (note the second COMMAND to touch a file)
ADD_CUSTOM_COMMAND(
OUTPUT ${module_name}.built
COMMAND ${KBUILD_CMD} modules
COMMAND cmake -E touch ${module_name}.built
COMMENT "Kernel make modules ${module_name}"
VERBATIM
)
Add a custom target, its always out of date, but if you want it to be called automatically add ALL otherwise you have to explicityly call make module_build, I guess this is what you want.
ADD_CUSTOM_TARGET("${module_name}_build" ALL
DEPENDS ${depends_module_ksyms}
${CMAKE_CURRENT_BINARY_DIR}/${module_name}.built
COMMENT "Building Kernel Module ${module_name}"
)

Related

Custom command / target run only for default build not install

I want to build my documentation (doxygen) alongside my project with CMake by default. I let CMake generate Makefiles. I know of these approaches so far:
1)
add_custom_target(doc ALL
COMMAND ${DOXYGEN_COMMAND})
2)
add_custom_command(
TARGET my-executable
POST_BUILD
COMMAND ${DOXYGEN_COMMAND})
The issue I have with the first approach is that the target is build both during build and install (i.e. when running make and when running make install). This is a no-go.
The issue with the second approach is that it is not actually correct: the documentation doesn't have to be built after the executable (in fact, it can be done in parallel even). Moreover I cannot build only the executable now.
Is there a way to create this custom command / target such that it is run only during make (building) and not during make install (installing) but independently from other targets such as executables?
Basically I'd need a "default target". Also I really want to avoid having to execute CMake recursively or make directly.
Just create a file, which existence means that documentation file have been built:
set(documentation_file ${CMAKE__BINARY_DIR}/docs_ready)
# Documentation target
add_custom_target(docs ALL DEPENDS ${documentation_file})
# Documentation command
add_custom_command(OUTPUT ${documentation_file}
COMMAND ${DOXYGEN_COMMAND}
# And mark that documentation is created
COMMAND ${CMAKE_COMMAND} -E touch ${documentation_file}
)
The solution given by #Tsyvarev works perfectly except for one issue:
Running make docs manually doesn't cause a re-build of the documentation because the "output file" ${documentation_file} is always considered up to date (there are no dependencies specified that could be newer).
Three workarounds I found:
Run make -B docs. The -B flags causes GNU Make to consider all targets out of date, and thus causes the documentation to be build.
Add a "manual docs" target which depends on first a docs-clean target which removes ${documentation_file} and then on docs itself (to build the documentation and the file), and run make docs-manual:
add_custom_target(docs-clean
COMMAND ${CMAKE_COMMAND} -E remove ${documentation_file})
add_custom_target(docs-manual)
add_dependencies(docs-manual docs-clean docs)
Note that I fear that this is just a dirty hack: AFAIK the order in which the dependencies (docs-clean and docs) are build isn't specified, and as they don't have a dependency between them, they could even be built in parallel.
Using add_custom_command with a TARGET docs-manual and PRE_BUILD (which runs the command before building dependencies) instead of the docs-clean target would've been perfect, but this only works for Visual Studio 7 or later.
Add a custom target that depends on docs but removes the generated ${documentation_file}:
add_custom_target(docs-manual
COMMAND ${CMAKE_COMMAND} -E remove ${documentation_file})
add_dependencies(docs-manual docs)
This works except for when running it the first time after a make docs, because then the generated file will still be there when docs is built.
edit: Use add_dependencies instead of DEPENDS of add_custom_target because the later is only intended for files, not for dependencies on targets.

cmake run script for install target?

I have a project where "installing" the code is not quite as simple as just copying some files. With a traditional Makefile, I would just create a make install target that runs a series of shell commands to do what I need.
But googling around has resulting in no examples of this (some things close, but not quite... i think). So basically, I want a custom command, that depends on the target executables, but produces nothing and runs a script that need not be portable to accomplish the "install"
Anyone have any examples of something like this?
CMake's install command allows for custom scripts. See the official documentation: install - Custom Installation Logic:
install([[SCRIPT <file>] [CODE <code>]]
[COMPONENT <component>] [...])
The SCRIPT form will invoke the given CMake script files during installation. If the script file name is a relative path it will be interpreted with respect to the current source directory. The CODE form will invoke the given CMake code during installation. Code is specified as a single argument inside a double-quoted string. For example, the code
install(CODE "MESSAGE(\"Sample install message.\")")
will print a message during installation.
To run custom shell script (or whatever program), combine install(CODE ...) with execute_process:
install(CODE "execute_process(COMMAND my_script.sh)")
This worked for me: use add_custom_target, then add the main target as a dependency to the custom target target.
# create custom target for setcap to be executed
add_custom_target(setcap ALL
WORKING_DIRECTORY ${OUTPUT_DIR}/bin
COMMAND ${CMAKE_COMMAND} -E 'sudo setcap cap_net_raw,cap_net_admin+eip ${}/bin/<executable name>)
# create a dependency on the custom target for main target, setcap depends on ${proj_name}
add_dependencies(setcap ${proj_name})

CMake build & link to library without installing to /usr/local or elsewhere

I'm trying to include an external library in a build environment that uses CMake. I'm not trying to install it on the local system (in fact I'd rather not do that, I don't want /usr/local clogged up with all kinds of libraries); I'd just like to have the resulting libxml2.a available for linking with my executable. I can build it fine with the following in CMakeLists.txt:
set (LIBXML_PATH ${MY_SOURCE_DIR}/libxml2-2.9.1)
add_custom_target (build_libxml ALL
COMMENT "Building libxml"
COMMAND ./configure --prefix=/tmp
COMMAND make
WORKING_DIRECTORY ${LIBXML_PATH}
)
But I'm still having trouble with the following:
1) Is this the right approach in the first place, for the general purpose of getting libraries built with configure and make into a CMake environment?
2) How do I get the resulting library (i.e. libxml2.a) under my build output directory?
3) How can I link to that library for my executable builds?
I tried a fiddly solution with
ADD_LIBRARY( xml2 STATIC libxml2.a )
but it seems like there must be a better way than hauling a whole library's contents into… a library.
Thanks.
You need to make it clearer to CMake what is going on here. All it can see now is that you have some custom command that it will run every time. Instead of using add_custom_target with COMMAND, I've found it better to use add_custom_command.
Something like this:
set (LIBXML_PATH ${MY_SOURCE_DIR}/libxml2-2.9.1)
add_custom_command(
OUTPUT libxml2.a
COMMENT "Building libxml"
COMMAND ./configure --prefix=/tmp
COMMAND make
WORKING_DIRECTORY ${LIBXML_PATH}
)
target_link_libraries(your-program libxml2.a)
By doing it this way, CMake can understand that your custom command's essential product is libxml2.a, and when CMake sees something depending on that, it will run the command (if the library doesn't exist already).

Is there way to tell CMake to generate several install rules?

Using CMake to generate GNU/Makefile as an example, I would like to be able to run different install rules, say make install and make install-doc.
Is there a way to tell CMake to generate this ?
You can add a custom target which invokes the cmake_install.cmake script in the outermost binary directory. This script is also invoked when you run the default install target.
add_custom_target(install-doc
COMMAND "${CMAKE_COMMAND}" "-DBUILD_TYPE=$<CONFIGURATION>"
"-DCOMPONENT=doc" "-P" "${CMAKE_BINARY_DIR}/cmake_install.cmake"
WORKING_DIRECTORY "${CMAKE_BINARY_DIR}")
The desired installation component has to be passed as the CMake variable COMPONENT. The build configuration can be set with the variable BUILD_TYPE. $<CONFIGURATION> is a generator expression which will be replaced by the currently active build configuration.

CMake Header Generator Updates

In CMake I currently have a simple Python script to generate a header, but if I update the script itself CMake won't re-run the script. Is there a way I can get CMake to do this?
It seems you are directly invoking your code generation script when cmake is run. While it is possible solution but it is definitely not a right way to use code generators with cmake.
I recommend you to use add_custom_command for your case:
add_custom_command(
OUTPUT generated.h
COMMAND ${PYTHON_EXECUTABLE} generator.py
DEPENDS generator.py
)
And next you can simple put your header to the list of source files passed to add_library/add_executable commands. cmake will automatically track all the dependencies and invoke your script.
Term DEPENDS generator.py informs cmake that it should regenerate header if script is changed.
With this approach file generated.h will be generated only at build time (when you run make or execute a build command in IDE). In contrast if you are running your script at cmake time (with execute_process command) then you have to rerun cmake to regenerate your file. Which is possible but you need to use some tricks to introduce a non-standard dependency.