Is it possible to build only a specific target when using ExternalProject? In particular, I need to download and build only the MPI version of the OpenCoarrays library. I tried
ExternalProject_Add(
OpenCoarrays-fallback
EXCLUDE_FROM_ALL 1
URL https://github.com/sourceryinstitute/opencoarrays/archive/1.0.1.tar.gz
BUILD_COMMAND make caf_mpi
)
but it builds both serial and MPI versions. If it is not possible, any hack is also welcome.
make install installs all flows of OpenCoarrays, so even you build only caf_mpi at build stage, caf_single is built automatically on install stage.
For install only caf_mpi library flow you can try to modify package sources using PATCH_COMMAND argument of ExternalProject_add command.
E.g, you may replace content of src/CMakeLists.txt file to this one:
add_subdirectory(mpi)
Probably, this will work.
Related
I'd like to build ta-lib via cmake's fetchcontent function in my
CMakeLists.txt
FetchContent_Declare(ta_lib
DOWNLOAD_DIR /tmp
URL http://prdownloads.sourceforge.net/ta-lib/ta-lib-0.4.0-src.tar.gz
CONFIGURE_COMMAND configure
BUILD_COMMAND make
INSTALL_COMMAND "make install"
)
FetchContent_MakeAvailable(ta_lib)
include_directories(${ta_lib_SOURCE_DIR}/include)
...
target_link_libraries(${PROJECT_NAME} PRIVATE ta_lib)
I checked that the script above is able to download and decompress the tar-ball, and populate cmake-build-release/_deps/ta_lib-src with the project source, but it fails to build via the desired configure && make && make install sequence. The cmake build doesn't complain, proceeding normally as in the headers are found, but ultimately fails with -lta_lib not found.
I tried BUILD_IN_SOURCE TRUE as well, however I get the error
External project ta_lib-populate has both BINARY_DIR and BUILD_IN_SOURCE!
How does one get the build and install step to actually kick in?
You are possibly missing a few things.
Your make install command most likely is trying to install to the default path, and that's not what you want. You need to add a prefix, ./configure --prefix <path>, and make it so that it's local to your project, e.g., tmp/, that you can find it later.
One you have that, you need identify where ta_lib is installed and links it manually using the target_link_libraries. Here, you most likely cannot just use ta_lib because it's surely not defined. You need to find the path to the library, if needed. Check your tmp/ folder for a clue, and consult the FetchContent documentation.
Unfortunately, I cannot think of a good example on the top of my head to add here.
We are converting a large Makefile based project to a CMake based system. I have numerous dependencies that I need to build prior to building our code. The first three dependencies are build using the following:
add_subdirectory(dependencies/libexpat/expat)
add_subdirectory(dependencies/libuuid-1.0.3)
add_subdirectory(dependencies/log4c-1.2.4)
expat has it's own CMakeLists.txt file and build with no problems. I would like to force expat to install to the staging directory before continuing. For libuuid I am using a ExternalProject_Add and as part of that process it does install into the staging directory.
Then when I build log4c, which needs expat, I can point it to the location of expat. Otherwise I would need to someone get access to the absolutely path for the temporary build location of expat.
I've tried to add the following after add_subdirectory:
add_subdirectory(dependencies/libexpat/expat)
add_subdirectory(dependencies/libuuid-1.0.3)
install(TARGETS expat LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/usr/lib)
add_subdirectory(dependencies/log4c-1.2.4)
Unfortunately CMake will not run expat's install code. How do I force expat to install after building but before it builds the rest of the project?
This looks like the primary use case for ExternalProject_Add, which is best used as a superbuild setup. This means that your top-level project (the "superbuild") does not build any actual code and instead consists only of ExternalProject_Add calls. Your "real" project is added as one of these "external" projects. This allows you to set up the superbuild with all dependencies, ordering, etc.
The workflow is then as follows:
Generate the superbuild project.
Build the superbuild project. This will build and install all dependencies, and also generate (and build) your real project.
Switch to the buildsystem generated for your real project and start doing further development using that. Your dependencies are already correctly set up and installed by the build of the superbuild project in the previous step.
I am trying to use the assimp library in a cross platform C++ project. I include the repo as a git submodule, so, effectively, if someone downloads my project they will also download the ASSIMP project.
After I go through the assimp build / CMAKE instructions and (on Linux) type make install and from then on in my project I can use:
target_link_libraries(${PROJECT_NAME} assimp)
However, there is no make install on Windows.
The only other way I have been able to include the library on Linux is to put (in my CmakeLists.txt file):
target_link_libraries(${PROJECT_NAME} ${CMAKE_SOURCE_DIR}/build/assimp/code/libassimp.so)
This is not cross platform as it hardcodes the name and location of the .so file which will not work on Windows.
How can I expose the library so that I can do something like target_link_libraries(${PROJECT_NAME} assimp) on all platforms?
My directory tree looks like:
- src
- include
- assimp
- bin
Where the assimp directory in the include directory is the git submodule
I think you're going about this the wrong way. You don't need to build assimp in a separate step from your project, and you don't need to make install to make it available.
There are a number of ways of handling third party dependencies in Cmake, since you've already chosen to submodule the assimp repository, we'll start there. Assuming assimp is located in the root of your repository in a directory called assimp/ this would be a barebones project including it:
cmake_minimum_required(VERSION 3.0)
project(Project myassimpproj)
# include your directories
include_directories(
${CMAKE_CURRENT_SOURCE_DIR}
)
# set any variables you might need to set for your app and assimp
set(BUILD_ASSIMP_TOOLS ON)
set(ASSIMP_BUILD_STATIC_LIB ON)
# add assimp source dir as a subdirectory, effectively making
# assimp's CMakeLists.txt part of your build
add_subdirectory(/path/to/assimp ${CMAKE_BINARY_DIR}/assimp)
add_executable(assimp_target main.cpp)
# be sure to link in assimp, use platform-agnostic syntax for the linker
target_link_libraries(assimp_target assimp)
There may be a better way of phrasing this using generator expressions syntax, but I haven't looked at assimp's CMakeLists.txt to know if it's supported (and this is a more generic way anyway.)
Not every project uses Cmake, so you may not be able to just add_subdirectory(). In those cases, you can effectively "fake" a user call to build them using their build commands on respective platforms. execute_process() runs a command at configure time add_custom_command() and add_custom_target() run commands at build time. You then create a fake target to make integration and cross your fingers they support Cmake someday.
You can also use the ExternalProject commands added to Cmake to create a custom target to drive download, update/patch, configure, build, install and test steps of an external project, but note that this solution and the next download the dependency rather than using the submodule'd source code.
Finally, I prefer to work with prebuilt dependencies, cuts down on build time, and they can be unit tested on their own outside of the project. Conan is an open source, decentralized and multi-platform package manager with very good support for C++ and almost transparent support for Cmake when used the right way. They have grown very stable in the last year. More information on how to use Conan with Cmake can be found here.
How to configure/hack cmake to build particular executable added with add_executable() but do not install it?
The executable is a unit test and will eventually be handled with add_test but for now I just want to strip test binaries off the release touching as little as possible.
Thanks
Since EXCLUDE_FROM_ALL has undefined behavior if combined with INSTALL (cmake tries to warn you, it doesn't matter if OPTIONAL is set), a solution guaranteed to work is more complicated.
You should:
Remove dependency of "install" target to "all" target (once, in the main CMakeLists.txt):
set(CMAKE_SKIP_INSTALL_ALL_DEPENDENCY true)
Add OPTIONAL to the INSTALL statements in your test libraries. Be aware of the possible bug of CMake I reported here
Collect separately all the targets you want to include in a custom "all_but_tests"
CMake add_custom_target depending on whole project being built (most difficult step)
Create a custom all_but_tests target:
add_custom_target(all_but_tests DEPENDS <<list of targets>>)
Add a dependency of the target install to all_but_tests
add_dependency(install all_but_tests)
(Sorry, this I have never tried, feedback is welcome)
Create a custom tests target:
add_custom_target(my_tests DEPENDS <<list of tests>>)
Then (supposing you are using make, but will work also for ninja):
You can call make install, which triggers make all_but_tests, and installs once built is complete.
You can call make my_tests, and then make install, in this case it will install everything. You can concatenate the commands like this
make my_tests && make install
or, since there is not difference in this case:
make [all] && make install
I was attracted by this question because I recently had to face a similar problem: Installing only one target and its dependencies
Edit:
add_dependency(install all_but_tests) will probably not work.
So, either you use an adequate workaround, or you call
make all_but_tests && make install
everytime you want to install "all_but_tests"
CMake will only install an executable target if you apply the install function to it, i.e.:
install(TARGETS ExecutableTest RUNTIME DESTINATION "bin")
To prevent the installation of the ExecutableTest for a Release build, add a CONFIGURATIONS restriction:
install(TARGETS ExecutableTest RUNTIME DESTINATION "bin" CONFIGURATIONS Debug)
Alternatively, you can make ExecutableTest an optional target, which is not built by default:
add_executable(ExecutableTest EXCLUDE_FROM_ALL ${ExecutableTestFiles})
and then optionally only install the ExecutableTest if it has been built explicitly:
install(TARGETS ExecutableTest RUNTIME DESTINATION "bin" OPTIONAL)
All optional test targets can be pooled in a super target to allow for building them in one step:
add_custom_target(MyTests DEPENDS ExecutableTest ExecutableTest2 ExecutableTest3)
I'm working on the cmake scripts for my project and I've run into a problem:
My project uses a 3rd party library (FreeImage), which has its own Makefile-based build system. I can build FreeImage just fine by simply running "make" (I'm using gnuwin32), which will build FreeImage using MinGW and produce:
FreeImage.lib
FreeImage.dll
Now my problem is twofold:
I want to execute "make" from my cmake script.
I want to link to the import lib (FreeImage.lib), and also make sure the DLL gets copied to the correct place so the EXE will run.
I know how to link to the LIB file, but I'm lost on the rest.
The folder structure is like this:
MyProject # main directory
MyProject/Libs/FreeImage # FreeImage root directory
MyProject/Libs/FreeImage/Dist # This is where FreeImage outputs go (LIB and DLL)
BTW: I'm running on Windows 7. I plan to build my project both with MSVC and MinGW.
Thanks!
EDIT:
I'm now trying to use ExternalProject_Add like so:
ExternalProject_Add(
FreeImage
PREFIX ./Libs/FreeImage
URL ./Libs/FreeImage
BUILD_COMMAND make
)
This gets me part of the way there, but doesn't totally work... it tries to configure things for me and tries to use nmake... ugh
In my opinion, there are two options:
In case you have put your FreeImage sources in your projects' source-tree, the easiest option may be to use the execute_process() command. Assuming FreeImage is in your projects' source-tree in "3rdparty/FreeImage/" you can do something like,
execute_process( COMMAND make WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/3rdParty/FreeImage )
Optionally, you can copy the dll from 3rdParty/FreeImage/bin into you own bin directory. And then you can write a FreeImageConfig.cmake for importing the library:
add_library( FreeImage IMPORTED )
set_target_properties( FreeImage PROPERTIES IMPORTED_LOCATION ${PROJECT_SOURCE_DIR}/3rdParty/FreeImage/lib )
...
The other option is to make use of the ExternalProject module. You can also take a look at this article from Kitware for an overview of this module. In essence, you specify the full chain of commands needed to get the source, configure the build, build the source and install it. All in your own CMakeLists.txt