Set WORKING_DIRECTORY for ExternalProject_Add CONFIGURE_COMMAND - cmake

I'm trying to add an Automake project as an external project.
The Automake configure script (usually run with ./configure) contains a relative path to a resource file. The file is found when I run configure manually, because my working directory is in the source directory. However, when I run configure with the ExternalProject_Add, it can't find the resource file because the working directory is CMAKE_CURRENT_BINARY_DIR.
ExternalProject_Add(zlib
SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}
CONFIGURE_COMMAND sh ${CMAKE_CURRENT_SOURCE_DIR}/configure
BUILD_COMMAND make)
How can I set the working directory for the configuration step so that the config script finds the required files?

In ExternalProject_Add configuration step is performed with build directory (BINARY_DIR option) being current, so you may set this option:
ExternalProject_Add(...
BINARY_DIR <dir>
...
)
For in-source builds (when build directory is the same as source directory), BUILD_IN_SOURCE option could be used as alternative to set BINARY_DIR option:
ExternalProject_Add(...
BUILD_IN_SOURCE 1
...
)
More info see at ExternalProject documentation page.

Related

How to add a dependency on a file for the configure step of ExternalProject_Add in cmake

I'm trying to add an external project, that doesn't use cmake, to my project that does use cmake:
include(ExternalProject)
ExternalProject_Add( MatrixSSL
SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/matrixssl
PREFIX ${CMAKE_CURRENT_BINARY_DIR}/matrixssl
CONFIGURE_COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/configure_matrixssl.sh
BUILD_COMMAND echo "Built!"
INSTALL_COMMAND echo "Installing!"
)
Here the script ${CMAKE_CURRENT_SOURCE_DIR}/configure_matrixssl.sh will do
whatever is required to configure that external project (aka, generate the Makefile's).
My problem is that when I edit configure_matrixssl.sh and re-run 'make', then
the configure step is not repeated. Therefore I want to add a dependency of
the 'configure step' on my script; when the modification time of my script is newer
than the modification time of the configure timestamp file, it should redo the
configuration step.
I tried,
ExternalProject_Add_Step( MatrixSSL configure
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/configure_matrixssl.sh
)
but this has no effect.
Then I tried,
ExternalProject_Add_Step( MatrixSSL configure
COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/configure_matrixssl.sh
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/configure_matrixssl.sh
)
but that gives me the error
CMake Error: Attempt to add a custom rule to output "/home/carlo/projects/aicxx/ai-evio-testsuite/ai-evio-testsuite-objdir/evio/matrixssl/src/MatrixSSL-stamp/MatrixSSL-configure.rule" which already has a custom rule.
Removing the CONFIGURE_COMMAND from the ExternalProject_Add has no effect.
How can I do this?

CMakeLists.txt not in root directory, can't do an automatic build

I have an issue with a repository not having its CMakeLists in the root directory, namely https://github.com/lz4/lz4
The CMakeLists.txt is in the subfolder contrib/cmake_unofficial.
I already checked similar questions on SO (Is it possible to have cmake build file (CMakeLists.txt) not in root in CLion, cmake - CMakeLists.txt is not in root folder (but is included in source)), but they only provide alternatives, and not a solution applicable to my situation.
Heres the cmake module I came up with:
if(ENABLE_LZ4)
message(STATUS "Using LZ4.")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DENABLE_LZ4")
# Enable ExternalProject CMake module
include(ExternalProject)
set(LZ4_SOURCE_DIR ${CMAKE_CURRENT_BINARY_DIR}/lz4)
set(LZ4_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/lib)
# Download and install lz4
ExternalProject_Add(
lz4
GIT_REPOSITORY https://github.com/lz4/lz4.git
GIT_TAG dev
SOURCE_DIR ${LZ4_SOURCE_DIR}
BINARY_DIR ${LZ4_BINARY_DIR}
INSTALL_COMMAND ""
CMAKE_ARGS
${LZ4_SOURCE_DIR}/contrib/cmake_unofficial
-DCMAKE_C_COMPILER=${CMAKE_C_COMPILER}
)
# Get lz4 source and binary directories from CMake project
ExternalProject_Get_Property(lz4 source_dir binary_dir)
# Create a liblz4 target to be used as a dependency by the program
add_library(liblz4 IMPORTED SHARED GLOBAL)
add_dependencies(liblz4 lz4)
include_directories(
${LZ4_SOURCE_DIR}/lib
)
set(LZ4_LIB ${LZ4_BINARY_DIR}/liblz4.so)
else()
message(STATUS "Not using LZ4.")
set(LZ4_LIB "")
endif()
Here the complete error output:
[ 0%] Performing update step for 'lz4'
Current branch dev is up to date.
[ 1%] Performing configure step for 'lz4'
CMake Error: The source directory "/****/build/lz4" does not appear to contain CMakeLists.txt.
Specify --help for usage, or press the help button on the CMake GUI.
CMakeFiles/lz4.dir/build.make:105: recipe for target 'lz4-prefix/src/lz4-stamp/lz4-configure' failed
make[2]: *** [lz4-prefix/src/lz4-stamp/lz4-configure] Error 1
CMakeFiles/Makefile2:72: recipe for target 'CMakeFiles/lz4.dir/all' failed
make[1]: *** [CMakeFiles/lz4.dir/all] Error 2
Makefile:94: recipe for target 'all' failed
make: *** [all] Error 2
I tried adding the path 'contrib/cmake_unofficial' to the CMAKE_ARGS variable (as seen in the module above), but it does not work (seems to be ignored?).
I also tried using PATCH_COMMAND to copy the CMakeLists.txt to the root before the build starts, but the relative paths of the file get messed up.
In other words, i need the cmake command to be called to build the library to be : cmake contrib/cmake_unofficial.
I also tried using CONFIGURE_COMMAND for this, but keep getting a file not found error for some reason (even though the path is correct).
The module has some other issues too, but I'm only interested in the non-root CMakeLists.
Thanks in advance!
ExternalProject separates download and source directories:
DOWNLOAD_DIR - a directory where downloading step is performed
SOURCE_DIR - a directory used as a source one when configuration step is performed
When use git for extract the project, note that git clone is called from the download directory, where it creates new directory with a project sources.
set(LZ4_DOWNLOAD_DIR ${CMAKE_CURRENT_BINARY_DIR}/lz4)
# Set a source dir based on the download one.
set(LZ4_SOURCE_DIR ${LZ4_DOWNLOAD_DIR}/lz4/contrib/cmake_unofficial)
set(LZ4_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/lib)
# Download and install lz4
ExternalProject_Add(
lz4
DOWNLOAD_DIR ${LZ4_DOWNLOAD_DIR} # Set download directory explicitely
GIT_REPOSITORY https://github.com/lz4/lz4.git
GIT_TAG dev
SOURCE_DIR ${LZ4_SOURCE_DIR}
BINARY_DIR ${LZ4_BINARY_DIR}
...
)
Probably not the correct way to do it, but this seems to work for me.
I used the CONFIGURE_COMMAND to call cmake on the correct directory.
Then use BUILD_COMMAND to call make
So essentially, it breaks down to this:
ExternalProject_Add(
lz4
GIT_REPOSITORY https://github.com/lz4/lz4.git
GIT_TAG dev
SOURCE_DIR ${LZ4_SOURCE_DIR}
BINARY_DIR ${LZ4_BINARY_DIR}
CONFIGURE_COMMAND cmake ${LZ4_SOURCE_DIR}/contrib/cmake_unofficial
BUILD_COMMAND make
INSTALL_COMMAND ""
CMAKE_ARGS
-DCMAKE_C_COMPILER=${CMAKE_C_COMPILER}
)

cmake's ExternalProject_Add: how to set source, build and install directories

I want to use ExternalProject_Add function to install cmake enabled projects. I need to control the building and installation processes. More specifically, I want that cmake build and install in specific directories.
There is an option to select a path where to put the source directory: SOURCE_DIR. Is there something equivalent for BUILD_DIR and INSTALL_DIR? I did not see anything alike.
There is a PREFIX option:
Root dir for entire project
What does it mean exactly? An how does cmake's ExternalProject_Add do the installation?
Edit:
This work, but I have no control over source directory and it does not install the library:
ExternalProject_Add(
wjelement-project
GIT_REPOSITORY "https://github.com/netmail-open/wjelement.git"
GIT_TAG "v1.2"
UPDATE_COMMAND ""
PATCH_COMMAND ""
TEST_COMMAND ""
INSTALL_COMMAND ""
#SOURCE_DIR "${MY_SOURCE_ROOT}/wjelement"
BINARY_DIR "${MY_BUILD_DIR}/wjelement"
INSTALL_DIR "${CCT_INSTALL_DIR}/wjelement"
)
If I uncomment SOURCE_DIR, it does not clone from GIT_CLONE but try to get source from SOURCE_DIR (and it fails because that's not what I expected...)
If I comment INSTALL_COMMAND "", then it try to install in C:/Program Files/wjelement, the default (apparently) and not in INSTALL_DIR
default path for source files seem to be ${CMAKE_BINARY_DIR}/wjelement-project-prefix/src
Another Stackoverflow question report problem (or at least non intuitive behavior) with INSTALL_DIR.

CMake External Project not Downloading

I am using CMake 3.5.1 with CLion, and I am attempting to download and install an external project from a URL. My CMakeLists.txt include:
include(ExternalProject)
set(EXTERNAL ${PROJECT_SOURCE_DIR}/external)
ExternalProject_Add(eigen_test
PREFIX ${EXTERNAL}/eigen
DOWNLOAD_DIR ${EXTERNAL}/eigen/download
SOURCE_DIR ${EXTERNAL}/eigen/src
BINARY_DIR ${EXTERNAL}/eigen/build
INSTALL_DIR ${EXTERNAL}/eigen/install
URL http://bitbucket.org/eigen/eigen/get/3.2.4.tar.gz
URL_MD5 4d0d77e06fef87b4fcd2c9b72cc8dc55
CONFIGURE_COMMAND cd <BINARY_DIR> && cmake -D CMAKE_INSTALL_PREFIX=$<INSTALL_DIR> <SOURCE_DIR>
)
When building, this directory structure is is created inside ${PROJECT_SOURCE_DIR}/external/
Although the cmake files exist to download and extract the project, these actions never occur. What am I doing wrong here?
I don't see a reason to pollute your project by downloading and building the library in ${PROJECT_SOURCE_DIR}, I always do that in ${CMAKE_BINARY_DIR}.
The eigen library uses CMakeLists.txt, it will work seamlessly as external project, you don't have to extensively configure each step. So CONFIGURE_COMMAND can be removed and the install prefix set with CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=...
This is the simplified and working configuration:
include(ExternalProject)
set(EXTERNALS_DIR ${CMAKE_BINARY_DIR}/external)
ExternalProject_Add(eigen_test
PREFIX ${EXTERNALS_DIR}
URL http://bitbucket.org/eigen/eigen/get/3.2.4.tar.gz
URL_MD5 4d0d77e06fef87b4fcd2c9b72cc8dc55
CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${EXTERNALS_DIR}/installed
)
How to use the library:
Add ${EXTERNALS_DIR}/installed/include to include directories
Build the eigen_test target

How to reuse extracted source with CMake's ExternalProject_Add?

I use the following CMake file to automatically download and compile the Boost libraries. After generating project files for my compiler, I run cmake --build . --config Debug and cmake --build . --config Release to build both variants. So I envoke the build process twice. Even though CMake is clever enough to not download the archive again if the checksum still matches, it extracts it into the source directory twice. Extraction takes a couple of minutes for the large Boost libraries, so I'd like to prevent CMake from doing it for the second build.
ExternalProject_Add(Boost
PREFIX ${BOOST_PREFIX}
TMP_DIR ${BOOST_PREFIX}/temp
STAMP_DIR ${BOOST_PREFIX}/stamp
#--Download step--------------
DOWNLOAD_DIR ${BOOST_PREFIX}/download
URL http://downloads.sourceforge.net/project/boost/boost/1.56.0/boost_1_56_0.tar.gz
URL_MD5 8c54705c424513fa2be0042696a3a162
#--Update/Patch step----------
UPDATE_COMMAND ""
#--Configure step-------------
SOURCE_DIR ${BOOST_PREFIX}/source
CONFIGURE_COMMAND ${BOOST_CONFIGURE_COMMAND}
#--Build step-----------------
BUILD_COMMAND ${BOOST_BUILD_EXECUTABLE} install
--build-dir=${BOOST_PREFIX}/build
--prefix=${BOOST_PREFIX}/install
variant=${BOOST_VARIANT}
link=${BOOST_LINK}
threading=multi
address-model=32
toolset=${BOOST_TOOLSET}
runtime-link=${BOOST_RUNTIME_LINK}
BUILD_IN_SOURCE 1
#--Install step---------------
INSTALL_COMMAND ""
)
In this particually example it would possible to just use variant=debug,release, but there are some other external dependencies in my project that I build this way. How can I make CMake only extract the archive if it downloaded a new one?
Create two projects: Foo-Release and Foo-Debug. Leave DOWNLOAD_COMMAND empty for the second project and make it depends on the first. Set SOURCE_DIR explicilty for both projects (point to the same directory). I.e.:
set(source_dir "${CMAKE_CURRENT_BINARY_DIR}/3rdParty/Foo/Source")
ExternalProject_Add(
Foo-Release
URL "..."
URL_HASH SHA1=...
SOURCE_DIR "${source_dir}"
...
)
ExternalProject_Add(
Foo-Debug
DOWNLOAD_COMMAND
""
SOURCE_DIR "${source_dir}"
...
)
add_dependencies(Foo-Debug Foo-Release)
Example