24

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:

  1. cmake -DCMAKE_INSTALL_DIR=dist
  2. <edit source code>
  3. make install
  4. 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?

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
theone
  • 243
  • 1
  • 2
  • 4
  • Related: [How to copy directory from source tree to binary tree?](https://stackoverflow.com/q/697560/183120) – legends2k Mar 31 '21 at 08:02
  • One of the options discussed in the above link is making a soft link instead of copying the all of the assets (which might be heavy with time and space wastage). – legends2k Mar 31 '21 at 08:06

3 Answers3

24

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})
Zitrax
  • 19,036
  • 20
  • 88
  • 110
fhd
  • 3,998
  • 2
  • 23
  • 18
11

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.

André
  • 18,348
  • 6
  • 60
  • 74
  • 1
    you should be aware that this make packaging of the project much more complicated, because for a package build cmake has to be executed again not to mention the extre cmake code you have to write. – Arne Sep 11 '14 at 02:16
3

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.

sebkraemer
  • 435
  • 3
  • 12