Search code examples
cmakebuild-systemninja

CMake and Ninja - "missing and no known rule to make it"


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.


Solution

  • 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)