14

I have this CMakeLists.txt file:

cmake_minimum_required(VERSION 3.8)

include(${CMAKE_CURRENT_SOURCE_DIR}/src/Something.cmake)

add_executable(execute main.cpp)
add_dependencies(somethingInterface Something)
add_dependencies(execute somethingInterface)

include_directories(
    ${CMAKE_CURRENT_SOURCE_DIR}/src
    )
target_compile_options(execute
    PRIVATE
        -std=c++11
        -g
)

add_library(library SHARED IMPORTED)
set_target_properties(library PROPERTIES IMPORTED_LOCATION ${CMAKE_BINARY_DIR}/library.so)
target_link_libraries(execute
    PRIVATE
        library
)

The library shared imported will be created in file Something.cmake, but tt must be built first. It was a add_custom_command(TARGET POST_BUILD...) in file Something.cmake.

I don't have any problem in using CMake builds here, but when I am using Ninja there an error.

ninja: error: 'library.so', needed by 'execute', missing and no known rule to make it

Or do you have any suggestion on how can you do this?

I think Ninja has a requirement that "library.so" must exist first, but CMake it is different. It checks whether the library is there at runtime.

Rox Rosales
  • 145
  • 1
  • 1
  • 6
  • "It was a `add_custom_command(TARGET POST_BUILD...)`" - What is the name of the **target** for this command? (the first argument in the elipsis). – Tsyvarev Feb 25 '19 at 13:00
  • add_library (somethingInterface empty.cpp) add_custom_command(TARGET somethingInterface POST_BUILD COMMAND ... #creating the "library" in the CMakeLists.txt ) It will built only once. – Rox Rosales Feb 25 '19 at 13:34
  • The name of the target is somethingInterface which is also the target for the add_library(somethingInterfacer empty.cpp) – Rox Rosales Feb 25 '19 at 14:00
  • Ok, your previous comment is shown updated only after I re-open the page. That is why I have asked clarification again. – Tsyvarev Feb 25 '19 at 14:34
  • Are you sure that exactly this `library.so` is created by your custom command? What if you ask ninja for explicitely build the `somethingInterface` target, and then ask ninja to build your `execute`? With correct setup this should work. – Tsyvarev Feb 25 '19 at 14:40
  • It does create it. Hmmmm ninja somethingInterface ninja execute this work but is there a automatic building it? :) using cmake. – Rox Rosales Feb 25 '19 at 15:20
  • 5
    Yes, it should be built automatically using target-level dependencies. But in ninja you probably need to specify `library.so` as a *BYPRODUCTS* for the command which creates it. See documentation for [add_custom_command](https://cmake.org/cmake/help/v3.7/command/add_custom_command.html) about this option. – Tsyvarev Feb 25 '19 at 16:48
  • What do you mean by *"CMake it's difference"* (seems incomprehensible)? Please respond by [editing your question](https://stackoverflow.com/posts/54866067/edit), not here in comments (***without*** "Edit:", "Update:", or similar - the question should appear as if it was written today). – Peter Mortensen Jan 26 '21 at 11:30

1 Answers1

19

There is indeed a divergence between the way Make and Ninja handle imported targets. What works with Make, may sometimes not work with Ninja.

In particular, the following lines of code work with Make, but not with Ninja:

ExternalProject_Add(extProject
    GIT_REPOSITORY <GIT_URL>
    CMAKE_CACHE_ARGS "-
    DCMAKE_INSTALL_PREFIX:STRING=${CMAKE_INSTALL_PREFIX}"
)
add_library(extLib SHARED IMPORTED)
add_dependencies(extLib extProject)
set_target_properties(extLib
    PROPERTIES IMPORTED_LOCATION ${CMAKE_INSTALL_PREFIX}/lib/libext.so
)

target_link_libraries(project extLib)

The CMake configure step will work fine, but at build time Ninja will complain:

ninja: error: '/path/to/libext.so', needed by 'project', missing and no known rule to make it

But this will work fine with Make.

You need to specify the library as a byproduct of the ExternalProject_Add comment as mentioned by Tsyvarev, as ExternalProject runs at build time.

The following works fine for me:

ExternalProject_Add(extProject
    GIT_REPOSITORY <GIT_URL>
    CMAKE_CACHE_ARGS "-
    DCMAKE_INSTALL_PREFIX:STRING=${CMAKE_INSTALL_PREFIX}"
    BUILD_BYPRODUCTS ${CMAKE_INSTALL_PREFIX}/lib/libext.so
)
add_library(extLib SHARED IMPORTED)
add_dependencies(extLib extProject)
set_target_properties(extLib
    PROPERTIES IMPORTED_LOCATION ${CMAKE_INSTALL_PREFIX}/lib/libext.so
)

target_link_libraries(project extLib)
Carlos Segarra
  • 785
  • 7
  • 9
  • (You don't think CMake is [supported by the syntax highlighting](https://meta.stackexchange.com/questions/184108/what-is-syntax-highlighting-and-how-does-it-work/184109#184109). If it was, it would probably be by `lang-cmake`) – Peter Mortensen Jan 26 '21 at 11:38
  • Yes, In my case I added add_library (externalLib SHARED empty.cpp) just to add dependencies to ninja. – Rox Rosales Jan 28 '21 at 01:47
  • 1
    Just want to add that you can use `` , `` (and other substitutions) inside `ExternalProject_Add`. For example, if the install step of you external project installs in 'lib/libfoo.a' inside a subdirectory of the build dir, you don't need to know what that subdirectory is, just say `/lib/libfoo.a`. These substitution variables are documented in the cmake ExternalProject_Add docs. – Reed Hedges Dec 15 '21 at 12:07