0

I am trying to build a 3rd-party dependency using ExternalProject_Add (in this case libpqxx):

ExternalProject_Add(libpqxx_ext
    GIT_REPOSITORY
        https://github.com/jtv/libpqxx
    GIT_TAG
        tags/7.4.1
    GIT_SHALLOW
        true
    PREFIX
        ext
    BINARY_DIR
        build
    CMAKE_ARGS
        -DSKIP_BUILD_TEST=on
    INSTALL_COMMAND
        ""
    BUILD_ALWAYS
        OFF
    )

Once this step completes, the libpqxx artifacts I then need to use in my project are located at:

  • header files: ${CMAKE_CURRENT_BINARY_DIR}/ext/src/libpqxx_ext/include
  • static library: ${CMAKE_CURRENT_BINARY_DIR}/build/src/libpqxx.a

Use the results in my project:

How do I make these artifacts available to my project?

I have tried the following:

set(LIB_PQXX_SRC_DIR   ${CMAKE_CURRENT_BINARY_DIR}/ext/src/libpqxx_ext)
set(LIB_PQXX_BUILD_DIR ${CMAKE_CURRENT_BINARY_DIR}/build/src)

add_library(libpqxx STATIC IMPORTED GLOBAL)
set_property(TARGET libpqxx APPEND PROPERTY IMPORTED_LOCATION             ${LIB_PQXX_BIN_DIR}/libpqxx.a)
set_property(TARGET libpqxx APPEND PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${LIB_PQXX_SRC_DIR}/include)
set_property(TARGET libpqxx APPEND PROPERTY INTERFACE_LINK_LIBRARIES      ${PostgreSQL_LIBRARIES})

add_dependencies(libpqxx libpqxx_ext)

This doesn't work because at configure time the ${LIB_PQXX_SRC_DIR}/include doesn't exist yet.

CMake Error in foo/CMakeLists.txt: Imported target "libpqxx" includes non-existent path

"/home/steve/src/foo/build/3rd-party/pqxx/ext/src/libpqxx_ext/include"

in its INTERFACE_INCLUDE_DIRECTORIES. Possible reasons include:

  • The path was deleted, renamed, or moved to another location.

  • An install or uninstall procedure did not complete successfully.

  • The installation package was faulty and references files it does not provide.

Adding add_dependencies to tell cmake that libpqxx_ext needs to be built before libpqxx doesn't work.

Note that if I remove libpqxx altogether, and then build my project (so that libpqxx_ext is built), and then add it, now everything works, because the ExternalProject_Add step has run... but obviously this breaks when I do a clean checkout, so it's not viable.

I also tried to tell cmake that the include dir is generated, but that had no effect

set_source_files_properties(${LIB_PQXX_SRC_DIR}/include PROPERTIES GENERATED TRUE)

Questions:

  • Is my use of add_library(libpqxx STATIC IMPORTED GLOBAL) to import the artifacts the correct / recommended way of using the result of ExternalProject_Add?

  • If it is, how can I tell cmake that ${LIB_PQXX_SRC_DIR}/include is a generated directory?

  • If it is not, what is the recommended way of making the result of ExternalProject_Add available to my project?

Steve Lorimer
  • 27,059
  • 17
  • 118
  • 213
  • try adding `ExternalProject_Add(... BUILD_BYPRODUCTS ${CMAKE_CURRENT_BINARY_DIR}/build/src/libpqxx.a)` – KamilCuk Mar 17 '21 at 09:08
  • "This doesn't work because at configure time the `${LIB_PQXX_SRC_DIR}/include` doesn't exist yet." - Why do you need this directory at **configure** time? If your executable needs these header for being compiled, then the compilation is occurred on the **build** time, not on the configure time. – Tsyvarev Mar 17 '21 at 09:11
  • @KamilCuk that doesn't work because the error is about the include path not existing – Steve Lorimer Mar 17 '21 at 09:13
  • @Tsyvarev I've updated the question with the error spat out by cmake. The issue is that when I try to link `libpqxx` to one of my project targets, during configure time cmake can't find the include dir... even though it would exist once the `libpqxx_ext` target is built – Steve Lorimer Mar 17 '21 at 09:14
  • 1
    Have you checked [that question](https://stackoverflow.com/questions/45516209/cmake-how-to-use-interface-include-directories-with-externalproject)? It seems to be exactly about your problem. (And it seems there is no "nice" resolution of the problem). – Tsyvarev Mar 17 '21 at 09:22
  • @Tsyvarev Ah - thanks! It does look like it will work, but what an ugly hack - `file(MAKE_DIRECTORY` Aargh! :) – Steve Lorimer Mar 17 '21 at 09:24
  • 1
    Actually, [the link](https://gitlab.kitware.com/cmake/cmake/-/issues/15052) from the answer contains another solution: declare IMPORTED library to refer only to the library file, and declare INTERFACE library to refer to the include directories. It seems, CMake checks existence of include directories only for the IMPORTED library, but not for the INTERFACE one. – Tsyvarev Mar 17 '21 at 09:31
  • @Tsyvarev I found a way to combine `FetchContent` and `ExternalProject_Add` to sidestep the issue. Added an answer to the [other SO question](https://stackoverflow.com/a/66671127/955273) you linked – Steve Lorimer Mar 17 '21 at 10:24

0 Answers0