My CMmake build script includes an "external native makefile". Target-all has a dependency with an "external make". This dependency is made by CMake.
CMakeLists.txt
|____( add_custom_target )_____ GNU make file
But Target-clean doesn't have a dependency with an "external make clean". I can't make dependency clean - external make clean. I can make a new custom-target (for example, newClean), and it has a dependency with "clean" and "external make clean". But "clean" and "newClean" exist. It may be the confusion.
How do I resolve this problem?
There are three possible solutions I can think of:
Make sure all output files from custom commands are listed in the OUTPUT line. They will then be removed as part of clean (this behaviour is mentioned with the CLEAN_NO_CUSTOM property).
Add extra files to the ADDITIONAL_MAKE_CLEAN_FILES directory property.
Create a new custom command which calls the normal clean target and your other make file. Example:
add_custom_target(really-clean
COMMAND "$(CMAKE)" --build "${CMAKE_BINARY_DIR}" clean
COMMAND cd "${CMAKE_BINARY_DIR}/otherproject" && make clean
)
Related
I need ExternalProject_Add to invoke just one command for an external project whose makefile does all the needed steps. I need to have that command be "make WITH_OPTION1=no WITH_OPTION2=no" in the directory at the top of the external project's source tree. This is one of a few dozen external projects we use. Most of them fit the model of 'configure; make; make install' but a good third don't and this is one that I thought would be easy.
If I try to have the make command invoked like this:
ExternalProject_Add(build-example
PREFIX "${CMAKE_CURRENT_BINARY_DIR}/example"
DEPENDS ""
SOURCE_DIR "${PROJECT_TOPDIR}/External/example"
CONFIGURE_COMMAND ""
BUILD_COMMAND COMMAND make WITH_OPTION1=no WITH_OPTION2=no
INSTALL_COMMAND "")
The resulting make step is done from the wrong directory and therefore the Makefile is not found.
If I add a -C option to the make command it seems to use the right directory, but it ignores the WITH_OPTION stuff. That doesn't compile properly, because those features use things I don't want to provide, and if it did work, I still don't want those features.
If I then add quotes around the entire desired make command, it goes wrong. Apparently the command is passed to 'sh' in such a way that sh fails.
If I use a mechanism to pass the command into a 'configure-file' step and invoke that file from the BUILD_COMMAND, then CMake actually tries to use a broken CMakeLists.txt file that's in the external project, and I wonder what makes CMake think that it should do so.
I just want to invoke the makefile properly, using CMake to organize that build within the dozens of other builds that have to be done to build the complete project.
With a growing codebase, it makes sense to organize it between separate repositories, each repo being a separate CMake-managed project.
Because of modularity, this usually means you end up in a situation where a CMake-managed project Application depends on another CMake-managed project Library, while both are internal code (i.e., code owned and maintained by your structure).
The automatic dependency recompilation issue
Then, if some sources in Library are modified, it needs to be recompiled in order to build Application. The question being:
Is it possible to have the "build Application" command (a button in an IDE, or a call to make on the command line) to first rebuild Library if Library files changed ?
I'd suggest to use the ExternalProject_Add command.
The documentation has slightly changed for the different versions:
CMake v2.8.9 ExternalProject
CMake v3.0. ExternalProject
CMake v3.3 ExternalProject
In case you encounter problems with getting the dependencies right, this thread might help you.
By looking at how the OpenChemistry parent-project does it, and with the confirmation by normanius's answer, it turns out this can be achieved with relatively few CMake script code.
It turns out that CMake CLI is offering an abstraction over the "build" action of the targeted build systems. See --build option.
ExternalProject_Add can be seen as a wrapper to use this CLI interface directly from CMake scripts.
Imagine there is a CMake-managed repository, building libuseful, and a separate CMake-managed repo, building appawesome with a dependency on libuseful.
find_package(libuseful CONFIG) # The usual way to find a dependency
# appawesome is the executable we are building, it depends on libuseful
add_executable(appawesome main.cpp)
target_link_libraries(appawesome libuseful)
Adding automatic rebuild
Then it is possible to make building appawesome systematically first try to rebuild libuseful with some code looking like:
ExternalProject_Add(EP_libuseful)
SOURCE_DIR <libuseful_sourcedir> # containing libuseful's root CMakeLists.txt
BINARY_DIR <libuseful_binarydir> # containing libuseful's CMakeCache.txt
BUILD_ALWAYS 1 # Always rebuild libuseful
)
add_dependencies(libuseful EP_libuseful)
The last line is quite important: find_package() in config mode should make a libuseful imported targed available. The call to ExternalProject_Add made a build target EP_libuseful available (which is a custom build step, building libuseful). The last line just makes sure that libuseful depends on its build step.
I want to add custom targets with cmake but, some of them must be "silent", because it isn't neccesary. For example, for clean custom commands:
// In CMakeLists.txt
add_custom_target(clean-temporaries
${CMAKE_COMMAND} -P clean-temporaries.cmake
COMMENT "Deleting temporary files"
)
// clean-temporaries.cmake
file(GLOB_RECURSE temporary_files "*[~#]")
file(REMOVE ${temporary_files})
$ cmake .
$ make clean-temporals
[100%] Deleting temporary files
[100%] Built target clean-temporaries
$ make clean
$
We can see that CMake prepares "make clean" to not show messages, but, how can I say to CMake I don't want messages in a custom target?
Try adding a minus at the beginning of the command you want to hide from the console.
-make clean
To deal with temporary files littering your source tree:
Encourage contributors to configure their editors so that temporary files end up in a common directory under their $HOME (eg: vim, emacs).
Encourage contributors to configure their global version control ignore files to always ignore the temporary files for their own work environment (eg. for git: vim, emacs).
Additionally exclude well known temporary file patterns in the version control's ignore file of each project, to be friendly to contributors who haven't yet implemented the two previous steps.
If you do that, it's likely that you don't have to put an additional 'optional' (ie. highly environment specific) step into your build system and you end up with a more generally applicable solution to the problem.
As an additional comment on your example code, I'd avoid building in the source tree and use out-of-source builds instead.
How do I create a CMakeLists.txt for gmock to configure only once?
I tried:
ADD_CUSTOM_TARGET( gmock DEPENDS ${CMAKE_CURRENT_LIST_DIR}/gmock-1.6.0/lib/.libs/libgmock.a COMMAND cd ${CMAKE_CURRENT_LIST_DIR}/gmock-1.6.0 && ./configure && make )
but this will do a ./configure every single time, even when I really only need to run it once.
As an aside, I'm open to using FIND_PACKAGE(), etc... for the long run so I don't need to make changes when updating gtest, but at this point, I'm just trying to get it to build without configuring every single time.
Do you want to have a build dependency on gtets or gmock source? If so, this thread on gtest mailing list may help. In short, simply ADD_DIRECTORY with your gtest or gmock source code and then you can depend on public library targets defined there.
Split the configure and the make call of gmock into two separate custom_targets and don't forget to add a dependency to each of them.
That is for the configure-target maybe the configure.in or any other file from gmock which makes it necessary to re-run configure and the configure-target to the make-target.
Then the make-target should be in dependency to one of your targets and not to the libgmock.a (which is generated by the make call).
HTH
I have a project in which the output of one custom command is used as the input to another, but in a different directory. So for example:
Directory lib/CMakeLists.txt contains:
add_custom_command(
OUTPUT libfoo.xx
COMMAND <command to build libfoo.xx>
)
add_custom_target(libfoo DEPENDS libfoo.xx)
Directory test/CMakeLists.txt contains:
add_custom_command(OUTPUT test.yy
COMMAND <command to build test.yy>
DEPENDS "${PROJECT_BINARY_DIR}/lib/libfoo.xx"
)
So I need to make sure that libfoo is build before test.yy. The docs say that the DEPENDS clause of add_custom_command() can only have file-level dependencies. Let's try that and see what happens:
No rule to make target 'lib/libfoo.xx', needed by 'test/test.yy'. Stop.
If on the other hand, I attempt to create a target-level dependency by saying DEPENDS libfoo, then the error changes to:
No rule to make target 'libfoo', needed by 'test/test.yy'. Stop.
So it seems neither file-level or target-level dependencies will work here. Is there any way to have the output from one custom command be the input to another custom command, in a different directory?
You could try in test/CMakLists.txt to add
add_custom_target(test DEPENDS test.yy)
and then to add
add_dependencies(test libfoo)
in your top-level CMakeLists.txt.
Disclaimer: I didn't test it and I'm a CMake beginner. Tell us if it works!