11

I have a CMake project that I want to build with the ExternalProject_Add command. In the CMAKE_ARGS parameter, I want to pass a list of prefix paths which contain CMake packages that are needed by the external project.

set(CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH} 
   ${CMAKE_SOURCE_DIR}/MyProject/cmake_packages
   ${CMAKE_SOURCE_DIR}/OtherProjects/cmake_packages)

ExternalProject_Add(MyProject
   DOWNLOAD_COMMAND ""
   SOURCE_DIR ${CMAKE_CURRENT_LIST_DIR}/source
   BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/MyProjectBuild
   INSTALL_DIR ${CMAKE_INSTALL_PREFIX}/MyProjectInstall
   CMAKE_ARGS 
              -DCMAKE_INSTALL_PREFIX=${CMAKE_INSTALL_PREFIX}/MyProjectInstall
              -DCMAKE_PREFIX_PATH=${CMAKE_PREFIX_PATH}
   )

Unfortunately, this won't work, as the resulting file MyProject-configure-Debug.cmake in the build directory contains something like this (simplyfied):

set(command "C:/Path/to/cmake.exe;-DCMAKE_PREFIX_PATH=D:/path/to/MyProject/cmake_packages;D:/path/to/OtherProjects/cmake_packages;-GCodeBlocks - Ninja;D:/path/to/my/source/dir")
execute_process(
  COMMAND ${command}
  RESULT_VARIABLE result
  OUTPUT_FILE "D:/.../MyProject-configure-out.log"
  ERROR_FILE "D:/.../MyProject-configure-err.log"
  )

As there will be a variable named command that contains a list which is passed to execute_process, only the first path of the CMAKE_PREFIX_PATH is passed to the externals CMake call as CMAKE_PREFIX_PATH. The other parameters are passed as commandline parameters to CMake.

I've found two solutions:

  1. This answer mentioned a solution with creating a new .cmake file that will be included by the external project.
  2. Also it would be possible to pass something like -DCMAKE_EXTRA_PREFIX_PATH to the CMAKE_ARGS parameter.

Both solutions require the external CMakeLists.txt project file to be modified either by including an extra .cmake file or by appending an extra path to CMAKE_PREFIX_PATH. But this is no option, as I want to leaf the external project untouched.

Is it possible to handle this without any additional .cmake file or extra variables?

Maybe I'm just missing some "quoting-magic" that has to be done?

tomvodi
  • 5,577
  • 2
  • 27
  • 38
  • Have you tried placing the `${CMAKE_PREFIX_PATH}` in the invocation of `ExternalProject_Add` in double quotes: `CMAKE_ARGS -DCMAKE_PREFIX_PATH="${CMAKE_PREFIX_PATH}"`? – Torbjörn Jul 31 '17 at 11:34
  • Yes, I've tried it with quite the same result. The quotes will be added to the `set(command ...)` one-to-one, containing the two paths. After that, it looks like there is no prefix path in the command anymore as they are quoted out: `set(command "...-DCMAKE_PREFIX_PATH="";-GCodeBlocks ..."` – tomvodi Jul 31 '17 at 11:48
  • I would try creating a variable that escapes the semicolons in the CMAKE_PREFIX_PATH, i.e. `\;`, then using that variable instead. I don't know of any neater method or if this method would actually work. – utopia Jul 31 '17 at 12:19

1 Answers1

15

After some more searching I've found on this page that the LIST_SEPARATOR parameter of ExternalProject_Add does the trick. Unfortunately the documentation about the use of this parameter isn't very meaningful.

Here is the solution for my problem:

set(CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH} 
   ${CMAKE_SOURCE_DIR}/MyProject/cmake_packages
   ${CMAKE_SOURCE_DIR}/OtherProjects/cmake_packages)

# Create a list with an alternate separator e.g. pipe symbol
string(REPLACE ";" "|" CMAKE_PREFIX_PATH_ALT_SEP "${CMAKE_PREFIX_PATH}")

ExternalProject_Add(MyProject
   DOWNLOAD_COMMAND ""
   SOURCE_DIR ${CMAKE_CURRENT_LIST_DIR}/source
   BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/MyProjectBuild
   INSTALL_DIR ${CMAKE_INSTALL_PREFIX}/MyProjectInstall
   LIST_SEPARATOR | # Use the alternate list separator
   CMAKE_ARGS 
              -DCMAKE_INSTALL_PREFIX=${CMAKE_INSTALL_PREFIX}/MyProjectInstall
              -DCMAKE_PREFIX_PATH=${CMAKE_PREFIX_PATH_ALT_SEP}
   )
tomvodi
  • 5,577
  • 2
  • 27
  • 38