I'm using an external library without CMake and building this library is a little tedious so I decided to use external scripts for that purpose:
one for configuration which runs the projects own build system, and
one for the actual build which simply runs MSBuild on the generated VS solution.
I want to copy the script to the directory where the archive is unpacked to, and execute it afterwards.
Current CMake File
file(TO_NATIVE_PATH ${CMAKE_CURRENT_LIST_DIR}/scripts/configure_OpenDDS_template.bat CONFIGURE_SCRIPT)
file(TO_NATIVE_PATH ${CMAKE_CURRENT_LIST_DIR}/scripts/build_OpenDDS_template.bat BUILD_SCRIPT)
ExternalProject_Add(OpenDDS
PREFIX OpenDDS
URL ${CLD}/OpenDDS-DDS-3.12.1.zip
CONFIGURE_COMMAND cmd /C "cd ../OpenDDS && copy ${CONFIGURE_SCRIPT} configure_OpenDDS.bat && call configure_OpenDDS.bat"
BUILD_COMMAND copy ${BUILD_SCRIPT} ${BUILD_COPY}
INSTALL_COMMAND "")
My question is whether there is a better or shorter or more elegant solution to have the absolute paths used in CONFIGURE_COMMAND and BUILD_COMMAND in correct Windows form than to use the conversion function from file. My current solution is acceptable for small projects in my opinion but you really want CMake to handle the path conversion for you without the excessive use of additional variables. I mean, CMake already handles the OS specific configuration of absolute paths for normal use but not within functions that execute pure OS commands like execute_process.
Im build libjpeg as external project. Its build normally.
Here projects folder structure:
${SOURCE_DIR}/
${SOME_BUILD_DIR}/
externals/
jpeg-9a/
jpeg-pre/
externals/
jpeg-9a/
jpeg-overlay/
CMakeLists.txt
tarballs/
jpegsrc.v9a.tar.gz
CMakeLists.txt
But tarball downloaded and unpacked again if I start building project from zero.
In other words I clean ${SOME_BUILD_DIR}/. At next build cmake do the next:
download tarballs/jpegsrc.v9a.tar.gz
unpack libjpeg into externals/jpeg-9a
copy externals/jpeg-overlay/CMakeLists.txt into externals/jpeg-9a
build libjpeg in ${SOME_BUILD_DIR}/externals/jpeg-9a/
Actually first 3 points can be omitted. But my interest only in first action. Is there way to prevent extra download?
Here is my ${SOURCE_DIR}/CMakeLists.txt:
cmake_minimum_required(VERSION 2.8)
include(ExternalProject)
set(EXTERNALS_DIR ${CMAKE_CURRENT_SOURCE_DIR}/externals)
set(JPEG_VERSION "9a")
set(JPEG_URI http://ijg.org/files/jpegsrc.v${JPEG_VERSION}.tar.gz)
set(JPEG_DIR ${EXTERNALS_DIR}/jpeg-${JPEG_VERSION})
ExternalProject_Add(
jpeg
STAMP_DIR ${CMAKE_BINARY_DIR}/externals/jpeg-pre
BINARY_DIR ${CMAKE_BINARY_DIR}/externals/jpeg-${JPEG_VERSION}
URL ${JPEG_URI}
SOURCE_DIR ${JPEG_DIR}
DOWNLOAD_DIR ${CMAKE_CURRENT_SOURCE_DIR}/tarballs
CMAKE_ARGS ""
UPDATE_COMMAND cmake -E copy_directory ${EXTERNALS_DIR}/jpeg-${JPEG_VERSION}-overlay/. ${JPEG_DIR}
INSTALL_COMMAND ""
TEST_COMMAND ""
)
See https://github.com/anton-sergeev/cmake_externalproject for details.
You should not place generated files in the source tree.
In your case, the problematic line is DOWNLOAD_DIR ${CMAKE_CURRENT_SOURCE_DIR}/tarballs. A cleaner approach would be to place the download in a directory in the binary dir and compile from there. Now, of course that means that when wiping the build directory it will also wipe the downloaded sources. Which kind of solves the problem of having to download a file that you already had, although probably not in the way you would have liked.
The thing is, this is by design. Wiping the binary dir is conceptually equivalent to telling CMake to start over from scratch. There is no point in trying to reuse stuff in this case because, well, you want to start from scratch. The correct workflow to enable reusing with CMake is simply: Do not wipe the build directory. Instead rely on make clean to enforce full rebuilds and only wipe the build directory if you want to perform a full reconfigure of CMake.
The only clean way to avoid redownload is to move the download out of the ExternalProject command. For instance, you could place the extracted files into the source tree and check them in as part of the project. Or have them downloaded by a custom execute_process command which implements the desired behavior.
If you run md5 jpegsrc.v9a.tar.gz, you can use the outputted hash with the ExternalProject URL_MD5 option.
ExternalProject_Add(
jpeg
STAMP_DIR ${CMAKE_BINARY_DIR}/externals/jpeg-pre
BINARY_DIR ${CMAKE_BINARY_DIR}/externals/jpeg-${JPEG_VERSION}
URL ${JPEG_URI}
URL_MD5 <md5_hash_of_downloaded_file>
SOURCE_DIR ${JPEG_DIR}
DOWNLOAD_DIR ${CMAKE_CURRENT_SOURCE_DIR}/tarballs
CMAKE_ARGS ""
UPDATE_COMMAND cmake -E copy_directory ${EXTERNALS_DIR}/jpeg-${JPEG_VERSION}-overlay/. ${JPEG_DIR}
INSTALL_COMMAND ""
TEST_COMMAND ""
)
I have a custom command that is executed if a directory exists. I need to know if the directory is not empty before executing another command.
Question: How to read, detect or get the number of files of a directory?
You can run regular CMake code as script using cmake -P as part of build process.
The script itself would contain somethng like
file(GLOB RESULT DIR)
list(LENGTH RESULT RES_LEN)
if(RES_LEN EQUAL 0)
# DIR is empty, do something
endif()
I'm pretty new to CMake, and read a few tutorials on how to use it, and wrote some complicated 50 lines of CMake script in order to make a program for 3 different compilers. This probably concludes all my knowledge in CMake.
Now my problem is that I have some source code, whose folder I don't want to touch/mess with when I make the program. I want that all CMake and make output files and folders to go into ../Compile/, so I changed a few variables in my CMake script for that, and it worked for sometime when I did something like this on my laptop:
Compile$ cmake ../src
Compile$ make
Where with that I had a clean output in the folder I'm in right now, which is exactly what I'm looking for.
Now I moved to another computer, and recompiled CMake 2.8.11.2, and I'm almost back to square one! It always compiles the thing into the src folder where my CMakeLists.txt is located.
The part where I choose the directory in my CMake script is this:
set(dir ${CMAKE_CURRENT_SOURCE_DIR}/../Compile/)
set(EXECUTABLE_OUTPUT_PATH ${dir} CACHE PATH "Build directory" FORCE)
set(LIBRARY_OUTPUT_PATH ${dir} CACHE PATH "Build directory" FORCE)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${dir})
set(CMAKE_BUILD_FILES_DIRECTORY ${dir})
set(CMAKE_BUILD_DIRECTORY ${dir})
set(CMAKE_BINARY_DIR ${dir})
SET(EXECUTABLE_OUTPUT_PATH ${dir})
SET(LIBRARY_OUTPUT_PATH ${dir}lib)
SET(CMAKE_CACHEFILE_DIR ${dir})
And now it always ends with:
-- Build files have been written to: /.../src
Am I missing something?
It sounds like you want an out of source build. There are a couple of ways you can create an out of source build.
Do what you were doing, run
cd /path/to/my/build/folder
cmake /path/to/my/source/folder
which will cause cmake to generate a build tree in /path/to/my/build/folder for the source tree in /path/to/my/source/folder.
Once you've created it, cmake remembers where the source folder is - so you can rerun
cmake on the build tree with
cmake /path/to/my/build/folder
or even
cmake .
if your current directory is already the build folder.
For CMake 3.13 or later, use these options to set the source and build folders
cmake -B/path/to/my/build/folder -S/path/to/my/source/folder
For older CMake, use some undocumented options to set the source and build folders:
cmake -B/path/to/my/build/folder -H/path/to/my/source/folder
which will do exactly the same thing as (1), but without the reliance on the current working directory.
CMake puts all of its outputs in the build tree by default, so unless you are liberally using ${CMAKE_SOURCE_DIR} or ${CMAKE_CURRENT_SOURCE_DIR} in your cmake files, it shouldn't touch your source tree.
The biggest thing that can go wrong is if you have previously generated a build tree in your source tree (i.e. you have an in source build). Once you've done this the second part of (1) above kicks in, and cmake doesn't make any changes to the source or build locations. Thus, you cannot create an out-of-source build for a source directory with an in-source build. You can fix this fairly easily by removing (at a minimum) CMakeCache.txt from the source directory. There are a few other files (mostly in the CMakeFiles directory) that CMake generates that you should remove as well, but these won't cause cmake to treat the source tree as a build tree.
Since out-of-source builds are often more desirable than in-source builds, you might want to modify your cmake to require out of source builds:
# Ensures that we do an out of source build
MACRO(MACRO_ENSURE_OUT_OF_SOURCE_BUILD MSG)
STRING(COMPARE EQUAL "${CMAKE_SOURCE_DIR}"
"${CMAKE_BINARY_DIR}" insource)
GET_FILENAME_COMPONENT(PARENTDIR ${CMAKE_SOURCE_DIR} PATH)
STRING(COMPARE EQUAL "${CMAKE_SOURCE_DIR}"
"${PARENTDIR}" insourcesubdir)
IF(insource OR insourcesubdir)
MESSAGE(FATAL_ERROR "${MSG}")
ENDIF(insource OR insourcesubdir)
ENDMACRO(MACRO_ENSURE_OUT_OF_SOURCE_BUILD)
MACRO_ENSURE_OUT_OF_SOURCE_BUILD(
"${CMAKE_PROJECT_NAME} requires an out of source build."
)
The above macro comes from a commonly used module called MacroOutOfSourceBuild. There are numerous sources for MacroOutOfSourceBuild.cmake on google but I can't seem to find the original and it's short enough to include here in full.
Unfortunately cmake has usually written a few files by the time the macro is invoked, so although it will stop you from actually performing the build you will still need to delete CMakeCache.txt and CMakeFiles.
You may find it useful to set the paths that binaries, shared and static libraries are written to - in which case see how do I make cmake output into a 'bin' dir? (disclaimer, I have the top voted answer on that question...but that's how I know about it).
There's little need to set all the variables you're setting. CMake sets them to reasonable defaults. You should definitely not modify CMAKE_BINARY_DIR or CMAKE_CACHEFILE_DIR. Treat these as read-only.
First remove the existing problematic cache file from the src directory:
cd src
rm CMakeCache.txt
cd ..
Then remove all the set() commands and do:
cd Compile && rm -rf *
cmake ../src
As long as you're outside of the source directory when running CMake, it will not modify the source directory unless your CMakeList explicitly tells it to do so.
Once you have this working, you can look at where CMake puts things by default, and only if you're not satisfied with the default locations (such as the default value of EXECUTABLE_OUTPUT_PATH), modify only those you need. And try to express them relative to CMAKE_BINARY_DIR, CMAKE_CURRENT_BINARY_DIR, PROJECT_BINARY_DIR etc.
If you look at CMake documentation, you'll see variables partitioned into semantic sections. Except for very special circumstances, you should treat all those listed under "Variables that Provide Information" as read-only inside CMakeLists.
Turning my comment into an answer:
In case anyone did what I did, which was start by putting all the build files in the source directory:
cd src
cmake .
cmake will put a bunch of build files and cache files (CMakeCache.txt, CMakeFiles, cmake_install.cmake, etc) in the src dir.
To change to an out of source build, I had to remove all of those files. Then I could do what #Angew recommended in his answer:
mkdir -p src/build
cd src/build
cmake ..
As of CMake Wiki:
CMAKE_BINARY_DIR
if you are building in-source, this is the same as CMAKE_SOURCE_DIR, otherwise this is the top level directory of your
build tree
Compare these two variables to determine if out-of-source build was started
You should not rely on a hard coded build dir name in your script, so the line with ../Compile must be changed.
It's because it should be up to user where to compile.
Instead of that use one of predefined variables:
http://www.cmake.org/Wiki/CMake_Useful_Variables
(look for CMAKE_BINARY_DIR and CMAKE_CURRENT_BINARY_DIR)
Starting from cmake 3.19 you can use also preset files, where you can specify among other useful things also the output binary dir:
{
"version": 2,
"cmakeMinimumRequired": {
"major": 3,
"minor": 19,
"patch": 0
},
"configurePresets": [
{
"name": "default",
"displayName": "Default",
"description": "Default build cfg",
"generator": "Unix Makefiles",
"binaryDir": "${sourceDir}/Compile",
"cacheVariables": {
},
"environment": {
}
}
]
}
Then just run cmake with --preset arg:
cmake --preset=default
Then just cd to your build dir and run make, in your case:
cd ./Compile
make
I've got a CMake project that contains code and a few data files (images to be precise).
My directory structure is like this:
src
data
src contains the source code, data the data files. CMake suggests out of source builds, so when I invoke make, I have the executable program, but not the data files, thus I cannot execute the program.
Of course, make install would copy my data files to the required location and make it work, therefore I develop like this right now:
cmake -DCMAKE_INSTALL_DIR=dist
<edit source code>
make install
dist/myprogram.exe
That's okay if I'm working with the command line and an editor, but I recently decided to move to Eclipse CDT. Generating an Eclipse project from CMake works great, but manually executing the install target from Eclipse is not so nice.
How do you people tackle this problem? Does your program have some clever algorithms to try and find its data directory even if it's not where the binary is? Or do you not use out of source builds?
configure_file should solve that problem.
I have a CMakeLists.txt file in my data directory which contains the following:
configure_file(data_file ${CMAKE_CURRENT_BINARY_DIR}/data_file COPYONLY)
This copies the specified file into the build directory when cmake is invoked, so it is available in the same location even in out of source builds.
configure_file does not support directories however while the file command does:
file(COPY assets DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
And if copying the files takes too much time (they are images...) you could make it even better by creating a "custom" data_header.h with configure_file which contains the paths to the data still in your source-directory.
This is what I do: I have a file "global_build_config.h.in" in my source, containing the following:
const char* const global_testdatapath = "#Test_Data_Path#";
and then use configure_file in CMake:
# Assume CMake knows a variable Test_Data_Path, it will be filled in automatically
# in the generated config/Global_Build_Config.h
configure_file( Global_Build_Config.h.in ${CMAKE_BINARY_DIR}/config/Global_Build_Config.h )
# The config directory should be added as a include-searchpath
include_directories( ${CMAKE_BINARY_DIR}/config/ )
I can then #include "Global_Build_Config.h" in my cpp files and refer to the fixed path.
Your question is a bit old, but in case you're still interested (or someone else), I have a similar scenario where I copy testdata for a unit-test target:
add_custom_command( TARGET ${UTEST_EXE_NAME}
POST_BUILD
COMMAND ${CMAKE_COMMAND} -E echo "Copying unit test data.."
COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_HOME_DIRECTORY}/utest/testdata ${CMAKE_BINARY_DIR}
)
So the main idea is to use a post-build target, and it is executed after each build. For me, it's not much data, and the filesystem caches it, so I don't feel the copy process at all. You could probably enhance this by copying with copy_if_different. In that case, however, you have to create a list of your image files and write a loop, because the command is file based. With the GLOB command, this shouldn't be hard to do if you need to.