Problem using FetchContent_Declare together with shared library - cmake

I'm having problem using FetchContent_Declare with a shared library. I'm trying to apply a modular design (instead of creating one mega-repository with 20 modules I'm allocating a dedicated repository to each module). I'm trying to use FetchContent_Declare in order to link dependant modules together (I'm not a fan of git-submodules since those require that user manually initialises them). The problem I'm having is that the DLL generated by the project fetched via the mentioned function isn't copied to the binary output of the parent project. Here is a dependency graph to make it more clear.
Repo A:
- bin
- bin-etc
- lib
- include
- project_a
.. header files ..
- src
- CMakeLists.txt : 1
.. source files ..
- CMakeLists.txt : 2
Repo B: Includes A
- bin
- bin-etc
- lib
- output
.. cmake files are built from here ..
- _deps
- project_a-src
- bin
.. here the DLL file is being generated ..
- include
- project_a
.. header files ..
- src
- CMakeLists.txt : 3
.. source files ..
- CMakeLists.txt : 4
The DLL file is being generated in ./output/_deps/project_a-src/bin instead of ./bin.
Here are my CMakeLists.txt files:
# CMakeLists.txt : 1
cmake_minimum_required(VERSION 3.16)
set(PROJECTNAME project_a)
set(PROJECTDIR "${CMAKE_CURRENT_SOURCE_DIR}")
file(GLOB_RECURSE inc "${CMAKE_CURRENT_SOURCE_DIR}/../include/*.hpp")
file(GLOB_RECURSE src "${CMAKE_CURRENT_SOURCE_DIR}/*.cpp")
source_group(TREE "${CMAKE_CURRENT_SOURCE_DIR}/../include" FILES ${inc})
source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR} FILES ${src})
if (MSVC)
add_compile_options(/W3) # warning level 3
add_compile_options(/MP) # Multi-processor compilation
endif()
add_library(
${PROJECTNAME}
SHARED
${inc}
${src}
)
target_include_directories(${PROJECTNAME} PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/../include/")
# CMakeLists.txt : 2 and 4
cmake_minimum_required(VERSION 3.16)
set_property(GLOBAL PROPERTY USE_FOLDERS ON)
set(CMAKE_SYSTEM_VERSION 10.0.19041.0)
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/bin-etc")
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/lib")
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/bin")
project(project_a LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 23)
set(CMAKE_CXX_STANDARD_REQUIRED)
add_subdirectory(src)
# CMakeLists.txt : 3
cmake_minimum_required(VERSION 3.16)
set(PROJECTNAME project_b)
set(PROJECTDIR "${CMAKE_CURRENT_SOURCE_DIR}")
file(GLOB_RECURSE inc "${CMAKE_CURRENT_SOURCE_DIR}/../include/*.hpp")
file(GLOB_RECURSE inc_src "${CMAKE_CURRENT_SOURCE_DIR}/*.hpp")
file(GLOB_RECURSE src "${CMAKE_CURRENT_SOURCE_DIR}/*.cpp")
source_group(TREE "${CMAKE_CURRENT_SOURCE_DIR}/../include" FILES ${inc})
source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR} FILES ${inc_src})
source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR} FILES ${src})
if (MSVC)
add_compile_options(/W3) # warning level 3
add_compile_options(/MP) # Multi-processor compilation
endif()
add_library(
${PROJECTNAME}
SHARED
${inc}
${inc_src}
${src}
)
target_include_directories(${PROJECTNAME} PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/../include/")
include(FetchContent)
FetchContent_Declare(project_a
GIT_REPOSITORY <REPO LINK>
GIT_TAG master)
FetchContent_MakeAvailable(project_a)
target_link_libraries(${PROJECTNAME} project_a)
What would be the solution to this problem? Should I use another approach for the design like this? Is adding a simple copy command to cmake the right solution?

Variables like CMAKE_RUNTIME_OUTPUT_DIRECTORY affects on the output directory for all further created libraries ... unless the variable is changed.
The project_a in CMakeLists.txt(2) does
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/bin")
unconditionally, so it changes the variable even if it is built as a subproject (with FetchContent).
Generally, any project in its root CMakeLists.txt could check, whether it is actually top-level project. And perform some settings only in case it is:
cmake_minimum_required(VERSION 3.21)
project(project_a LANGUAGES CXX)
if (PROJECT_IS_TOP_LEVEL)
# Do global settings only if we are top-level project.
set_property(GLOBAL PROPERTY USE_FOLDERS ON)
set(CMAKE_SYSTEM_VERSION 10.0.19041.0)
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/bin-etc")
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/lib")
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/bin")
endif()
# Other settings are treated as project-specific,
# so could be done in "subproject mode" too.
set(CMAKE_CXX_STANDARD 23)
set(CMAKE_CXX_STANDARD_REQUIRED)
add_subdirectory(src)
Note, that variable PROJECT_IS_TOP_LEVEL appears only in CMake 3.21. For detect, whether the project is top-level in older CMake versions, consult that question and its answers: How to detect if current scope has a parent in CMake?.

Related

How to use find_package after add_subdirectory

I am trying to import a third party package into my project. So I've been following:
https://cliutils.gitlab.io/modern-cmake/chapters/install/installing.html
But this fails with:
/tmp/top-level/bin/extern/MyLib
CMake Error at bin/extern/MyLib/MyLibConfig.cmake:12 (include):
include could not find load file:
/tmp/top-level/bin/extern/MyLib/MyLibTargets.cmake
Call Stack (most recent call first):
CMakeLists.txt:6 (find_package)
What am I missing from the documentation ? For reference, my top level cmakelists.txt is:
cmake_minimum_required(VERSION 3.18)
project(top-level)
add_subdirectory(extern)
find_package(MyLib CONFIG REQUIRED HINTS
${CMAKE_CURRENT_BINARY_DIR}/extern/MyLib)
And the cmakelists.txt file for 'MyLib' is:
cmake_minimum_required(VERSION 3.18)
project(MyLib VERSION 1.0 LANGUAGES C)
add_library(MyLib mylib.c)
add_library(MyLib::MyLib ALIAS MyLib)
install(
TARGETS MyLib
EXPORT MyLibTargets
LIBRARY DESTINATION lib
ARCHIVE DESTINATION lib
RUNTIME DESTINATION bin
INCLUDES
DESTINATION include)
include(CMakePackageConfigHelpers)
write_basic_package_version_file(
MyLibConfigVersion.cmake
VERSION ${PACKAGE_VERSION}
COMPATIBILITY AnyNewerVersion)
install(
EXPORT MyLibTargets
FILE MyLibTargets.cmake
NAMESPACE MyLib::
DESTINATION lib/cmake/MyLib)
configure_file(MyLibConfig.cmake.in MyLibConfig.cmake #ONLY)
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/MyLibConfig.cmake"
"${CMAKE_CURRENT_BINARY_DIR}/MyLibConfigVersion.cmake"
DESTINATION lib/cmake/MyLib)
The error message is self-explanatory:
You use script MyLibConfig.cmake from the build directory, and this script attempts to load the script MyLibTargets.cmake created by install(EXPORT MyLibTargets).
But the latter script is intended to work only after the project will be installed, it cannot work while the project is being built.
Actually, the whole call find_package(MyLib) is not needed in that situation:
since current project builds MyLib, the target MyLib::MyLib is already accessible for you.
If you want to make your top-level project to be flexible, so it would work both in cases MyLib is already installed or just being built, then you could use find_package conditionally:
cmake_minimum_required(VERSION 3.18)
project(top-level)
# This project could be built as standalone.
# In that case 'MyLib' is assumed to be already installed.
#
# Also, this project could work as a subproject of some other project,
# which also builds `MyLib` via 'add_subdirectory(MyLib)'.
if(NOT TARGET MyLib::MyLib)
find_package(MyLib CONFIG REQUIRED)
endif()
# ... use MyLib via 'MyLib::MyLib' target.
Alternatively, you may write MyLibConfig.cmake script in a manner, which allows it to be used even if MyLib is currently being built.
if(TARGET MyLib::MyLib)
return()
endif()
# ... usual content of the config file.
In that case, CMakeLists.txt for the root project could be simplified:
cmake_minimum_required(VERSION 3.18)
project(top-level)
# Normal use case is that 'MyLib' is already installed.
# But the project could work as a subproject in other scenarios.
#
# In those scenarios, a parent project should care about
# 'find_package' to work.
find_package(MyLib CONFIG REQUIRED)
# ... use MyLib via 'MyLib::MyLib' target.
The usage of the project in case of 'MyLib' being built could be as follows:
- CMakeLists.txt (outer)
- MyLib
- CMakeLists.txt (MyLib)
- top_level
- CMakeLists.txt ("top-level")
Outer CMakeLists.txt:
cmake_minimum_required(VERSION 3.18)
project(outer)
add_subdirectory(MyLib)
# Help inner project to find config file for MyLib.
#
# Here we use *internal* knowledge of MyLib project,
# that it generates 'MyLibConfig.cmake' directly in its build directory.
#
# Note: find_package expects 'XXX_DIR' variable to be CACHE one.
set(MyLib_DIR "${CMAKE_CURRENT_BINARY_DIR}/MyLib"
CACHE INTERNAL "Directory with MyLibConfig.cmake"
)
add_subdirectory(top_level)

What does this CMake error mean? And how could I go about resolving it?

I get this error, which I've been trying to understand for some time now but getting nowhere.
add_library cannot create target "Plugin" because another target
with the same name already exists. The existing target is a shared library created
in source directory "D:/CHAI3D/SOFA/src/applications/plugins/plugin".
See documentation for policy CMP0002 for more details.
Below is the CMakelists.txt added for reference. I tried to remove the unnecessary code. So far, I've tried allowing duplicate targets with set(ALLOW_DUPLICATE_CUSTOM_TARGETS TRUE)
But to no avail
cmake_minimum_required(VERSION 3.1)
project(Plugin VERSION 21.06.99)
# Policies
cmake_policy(SET CMP0079 NEW)
set(ALLOW_DUPLICATE_CUSTOM_TARGETS TRUE)
set (PLUGIN_VERSION ${PROJECT_VERSION})
set(HEADER_FILES
src/initPlugin.h
...
)
set(SOURCE_FILES
src/initPlugin.cpp
...
)
file(GLOB_RECURSE RESOURCE_FILES "*.md" "*.psl" "*.py" "*.pyscn" "*.scn" "*.ah")
add_library(${PROJECT_NAME} SHARED ${HEADER_FILES} ${SOURCE_FILES} ${RESOURCE_FILES} )
target_include_directories(${PROJECT_NAME} PUBLIC "$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/src>")
set_target_properties(${PROJECT_NAME} PROPERTIES COMPILE_FLAGS "-DSOFA_BUILD_PLUGIN")
target_link_libraries(${PROJECT_NAME} SofaCore SofaConstraint SofaSimpleFem SofaBaseMechanics SofaRigid SofaBaseVisual SofaOpenglVisual)
## Install rules for the library and headers; CMake package configurations files
sofa_create_package_with_targets(
PACKAGE_NAME ${PROJECT_NAME}
PACKAGE_VERSION ${PROJECT_VERSION}
TARGETS ${PROJECT_NAME} AUTO_SET_TARGET_PROPERTIES
INCLUDE_SOURCE_DIR "src"
INCLUDE_INSTALL_DIR ${PROJECT_NAME}
RELOCATABLE "plugins"
)
SET_PROPERTY(GLOBAL PROPERTY USE_FOLDERS ON)
SET_PROPERTY(TARGET ${PROJECT_NAME} PROPERTY FOLDER "plugins")

Produce .lib of header-only library that depends on external resources

EDIT: I've read up and understood the initial issue was caused by scanning-header-only not having cpp files and thus a lib file not being generated. Edited the question to reflect that extra understanding:
My current project folder structure and relevant CMakeLists content:
leveling
├── CMakeLists.txt: add_subdirectory(deps)
└── deps
├── CMakeLists.txt: add_subdirectory(scanning-header-only)
└── scanning
├── CMakeLists.txt: add_subdirectory(deps)
│ add_library(scanning-header-only file.h)
│ target_include_directories(scanning-header-only PUBLIC ${CMAKE_CURRENT_LIST_DIR}/deps/tinyxml2)
│ target_link_libraries(scanning-header-only PUBLIC tinyxml2)
└── deps
├── CMakeLists.txt: add_subdirectory(tinyxml2)
└── tinyxml2
But a scanning-header-only library file is not being generated, and thus the root project can't target_link_libraries(leveling scanning-header-only) and has had to target_include_directories(leveling ${CMAKE_CURRENT_LIST_DIR}/deps/scanning-header-only/deps/tinyxml2)
Is it possible to target_link_library a header-only library that depends on external resources?
I see that a header-only library without external resource dependency could be add_library(.. INTERFACE), but I'm failing to do so with the dependency on tinyxml2
A dirty workaround is adding and empty cpp file to scanning-header-only so a lib file is generated, but is there a correct way to do this?
Here is minimal example v1: https://www.dropbox.com/s/r1lbajz3xoat1bg/leveling-header-only-test%20v1.zip?dl=0
leveling CMakeLists.txt:
cmake_minimum_required(VERSION 3.8)
set(LEVELING_NAME leveling)
project(${LEVELING_NAME})
#
# To put tinyxml.dll next to the executable, to workaround having to make tinyxml2.dll reachable in PATH
#
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
math(EXPR platform_bits "${CMAKE_SIZEOF_VOID_P} * 8")
set(platform_dir bin/${CMAKE_SYSTEM_NAME}-${platform_bits})
foreach(config DEBUG RELEASE RELWITHDEBINFO MINSIZEREL)
foreach(var
CMAKE_ARCHIVE_OUTPUT_DIRECTORY_${config}
CMAKE_LIBRARY_OUTPUT_DIRECTORY_${config}
CMAKE_RUNTIME_OUTPUT_DIRECTORY_${config}
)
set(${var} "${CMAKE_BINARY_DIR}/${platform_dir}/${config}")
string(TOLOWER "${${var}}" ${var})
endforeach()
endforeach()
#
# ----------------------------------------------------------------------
#
add_subdirectory(deps)
add_executable(${LEVELING_NAME} main.cpp)
target_include_directories(${LEVELING_NAME} PUBLIC
${CMAKE_CURRENT_LIST_DIR}/deps/scanning
)
target_link_libraries(${LEVELING_NAME}
xml-reading
)
set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT ${LEVELING_NAME}) # Set Startup Project in VS. Implemented in CMake v3.6
set_target_properties(${LEVELING_NAME} PROPERTIES VS_DEBUGGER_WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}") # Set Working Directory of project in VS. Implemented in CMake v3.8
scanning CMakeLists.txt
cmake_minimum_required(VERSION 3.8)
set(XML_NAME xml-reading)
project(${XML_NAME})
#
# To put tinyxml.dll next to the executable, to workaround having to make tinyxml2.dll reachable in PATH
#
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
math(EXPR platform_bits "${CMAKE_SIZEOF_VOID_P} * 8")
set(platform_dir bin/${CMAKE_SYSTEM_NAME}-${platform_bits})
foreach(config DEBUG RELEASE RELWITHDEBINFO MINSIZEREL)
foreach(var
CMAKE_ARCHIVE_OUTPUT_DIRECTORY_${config}
CMAKE_LIBRARY_OUTPUT_DIRECTORY_${config}
CMAKE_RUNTIME_OUTPUT_DIRECTORY_${config}
)
set(${var} "${CMAKE_BINARY_DIR}/${platform_dir}/${config}")
string(TOLOWER "${${var}}" ${var})
endforeach()
endforeach()
#
# ----------------------------------------------------------------------
#
add_subdirectory(deps)
add_library(${XML_NAME} INTERFACE CamerasXML.h)
target_include_directories(${XML_NAME} INTERFACE
${CMAKE_CURRENT_LIST_DIR}/deps/tinyxml2
)
target_link_libraries(${XML_NAME}
INTERFACE tinyxml2
)
which yields
CMake Error at deps/scanning/CMakeLists.txt:33 (add_library):
add_library INTERFACE library requires no source arguments.
A .lib is when you create a STATIC (.lib) or SHARED (.lib and .dll) library on Windows. What you want is an INTERFACE library and it generates no files. http://mariobadr.com/creating-a-header-only-library-with-cmake.html has an example. Then you can use the following commands listed here, https://cmake.org/cmake/help/latest/command/add_library.html#interface-libraries, to populate the interface. Notice that it uses INTERFACE not PUBLIC.
target_link_libraries(INTERFACE),
target_link_options(INTERFACE),
target_include_directories(INTERFACE),
target_compile_options(INTERFACE),
target_compile_definitions(INTERFACE), and
target_sources(INTERFACE),
I've never actually used this but I assume it works as documented.
A simple add_library(${XML_NAME} INTERFACE) (not specifying any source files), while having target_include_directories(${XML_NAME} INTERFACE ${CMAKE_CURRENT_LIST_DIR}/deps/tinyxml2) and target_link_libraries(${XML_NAME} INTERFACE tinyxml2) will do the trick.
The tinyxml2 includes are made available to the parent project, and the tinyxml2 library is linked in the parent project.

Best way to add include directories of root project to a subdirectory in CMake

I have a project with a CMakeLists.txt at the root, which includes a project in a subdirectory test/ using add_subdirectory with the flag EXCLUDE_FROM_ALL. The tests need all of the include directories of the parent project. What would be the most elegant way to do this?
CMakeLists.txt
CMAKE_MINIMUM_REQUIRED(VERSION 3.1)
SET(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/Modules")
PROJECT(autoffi CXX)
SET(CMAKE_CXX_STANDARD 11)
SET(AutoFFI_VERSION_MAJOR 0)
SET(AutoFFI_VERSION_MINOR 1)
SET(Boost_USE_STATIC_LIBS OFF)
FIND_PACKAGE(BOOST 1.50 COMPONENTS system filesystem REQUIRED)
FIND_PACKAGE(LLVM 3.9 REQUIRED CONFIG)
ADD_DEFINITIONS(${LLVM_DEFINITIONS})
FIND_PACKAGE(Clang REQUIRED)
CONFIGURE_FILE(
"${PROJECT_SOURCE_DIR}/include/env.h.in"
#"${PROJECT_BINARY_DIR}/include/env.h"
"${PROJECT_SOURCE_DIR}/include/env.h" # added to VCS
)
INCLUDE_DIRECTORIES(
#"${PROJECT_BINARY_DIR}"
"${PROJECT_SOURCE_DIR}/include"
"${CLANG_INCLUDE_DIRS}"
"${Boost_INCLUDE_DIRS}"
)
# The C++ interface
ADD_LIBRARY(autoffiCore src/Type.cpp)
# FIXME: boost package finder seems to be broken
TARGET_LINK_LIBRARIES(autoffiCore boost_filesystem boost_system)
ADD_LIBRARY(autoffiBin src/BinFormat.cpp)
TARGET_LINK_LIBRARIES(autoffiBin autoffiCore)
ADD_LIBRARY(autoffiClang src/ClangEngine.cpp)
llvm_map_components_to_libnames(llvm_libs all)
TARGET_LINK_LIBRARIES(autoffiClang autoffiCore ${llvm_libs} ${CLANG_LIBS})
# The C interface
ADD_LIBRARY(autoffi src/PrettyPrinter.cpp src/libautoffi.cpp)
TARGET_LINK_LIBRARIES(autoffi autoffiBin autoffiClang)
set_target_properties(autoffiCore autoffiBin autoffiClang autoffi PROPERTIES DEFINE_SYMBOL BUILDING_SHARED)
# CLI Tools
ADD_EXECUTABLE(afdump src/dump.cpp src/PrettyPrinter.cpp)
TARGET_LINK_LIBRARIES(afdump autoffiBin)
ADD_EXECUTABLE(afconvert src/convert.cpp)
TARGET_LINK_LIBRARIES(afconvert autoffiBin)
ADD_EXECUTABLE(afcompile src/tooling.cpp src/PrettyPrinter.cpp)
TARGET_LINK_LIBRARIES(afcompile autoffiClang ${CLANG_LIBS} autoffiBin)
# Testing
ENABLE_TESTING()
ADD_TEST(headerASTDump afcompile test/assets/basic.h)
test/CMakeLists.txt
CMAKE_MINIMUM_REQUIRED(VERSION 2.8)
project("AutoFFI Tests")
SET(CMAKE_CXX_STANDARD 11)
SET(GTEST_ROOT "${CMAKE_CURRENT_LIST_DIR}/gtest")
find_package(GTest REQUIRED)
INCLUDE_DIRECTORIES(${AUTOFFI_INCLUDE_DIRS} ${GTEST_INCLUDE_DIRS})
ADD_EXECUTABLE(autoffiTest libautoffi.cpp core.cpp formats.cpp clang.cpp)
TARGET_LINK_LIBRARIES(autoffiTest ${GTEST_BOTH_LIBRARIES})
SET_TARGET_PROPERTIES(autoffiTest PROPERTIES OUTPUT_NAME runtests)
You are keeping your main directory and your subdirectory test in completely separated projects. I suppose you are building test by invoking separately cmake and make a second time. No surprise that the include_directories of your main project as no impact on the test project.
You mention the command add_subdirectory, (that should be used to include test in from your main directory) but you are actually not using it...
If you're using include_directories() to add dirs, those should propagate down into targets in the test subdir. Beware though that relative paths are relative to the current source dir:
include_directories: Add include directories to the build.
include_directories([AFTER|BEFORE] [SYSTEM] dir1 dir2 ...)
Add the given directories to those the compiler uses to search for include files. Relative paths are interpreted as relative to the current source directory.
cmake docs

Provide pre-compiled library as install(TARGET ...) to other projects in CMake

I want to define a CMakeLists which is able to export a precompiled library to an out of source output folder.
This is how it currently look like:
cmake_minimum_required (VERSION 3.3)
project(duktape)
include_directories("./code" "./code")
file(GLOB allCodeFiles
"./code/*.h"
#"./code/*.cpp"
)
add_library(${PROJECT_NAME} SHARED IMPORTED)
set_property(TARGET ${PROJECT_NAME} PROPERTY IMPORTED_LOCATION ./bin/duktape.dll)
set_property(TARGET ${PROJECT_NAME} PROPERTY IMPORTED_IMPLIB ./lib/duktape.lib)
export(PACKAGE ${PROJECT_NAME})
Message(INSTALL_INCLUDE_DIR=${INSTALL_INCLUDE_DIR})
install(TARGETS ${PROJECT_NAME}
RUNTIME DESTINATION "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}"
ARCHIVE DESTINATION "${CMAKE_ARCHIVE_OUTPUT_DIRECTORY}"
LIBRARY DESTINATION "${CMAKE_LIBRARY_OUTPUT_DIRECTORY}"
PUBLIC_HEADER DESTINATION "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${PROJECT_NAME}/code"
)
My current understanding of the install(TARGETS ...) is that it moves my libs to my out of soruce output folder and shares the headers to the project (some binary maybe) which depends on the lib.
The problem is that the export than tells:
CMake Error at C:/Test1/duktape-1.4.0.win32/CMakeLists.txt:30 (install):
install TARGETS given target "duktape" which does not exist in this directory.
[Edit]:
I still found no solution to just define a "project" to link a pre-compiled lib for integration purpose as a dependency to other projects?! I saw this kind of question ~10 times on google etc. and still can't belive that i didnt found one clear easy answer for this generic thing...
This is what i now end up with trying:
cmake_minimum_required (VERSION 3.3)
project(duktape)
#include(${CMAKE_BINARY_DIR}/DebugCmakeStuff.wtf)
# https://cmake.org/cmake/help/v3.0/command/add_library.html
add_library(${PROJECT_NAME} SHARED IMPORTED GLOBAL)
set_target_properties(${PROJECT_NAME} PROPERTIES INTERFACE_INCLUDE_DIRECTORIES ./include)
set_target_properties(${PROJECT_NAME} PROPERTIES INTERFACE_COMPILE_DEFINITIONS "")
set_target_properties(${PROJECT_NAME} PROPERTIES INTERFACE_COMPILE_OPTIONS "")
set_target_properties(${PROJECT_NAME} PROPERTIES IMPORTED_LOCATION ${CMAKE_CURRENT_SOURCE_DIR}/bin/duktape.dll)
set_target_properties(${PROJECT_NAME} PROPERTIES IMPORTED_LOCATION ${CMAKE_CURRENT_SOURCE_DIR}/lib/duktape.lib)
set_target_properties(${PROJECT_NAME} PROPERTIES IMPORTED_LOCATION_DEBUG ${CMAKE_CURRENT_SOURCE_DIR}/bin/duktape.dll)
set_target_properties(${PROJECT_NAME} PROPERTIES IMPORTED_LOCATION_DEBUG ${CMAKE_CURRENT_SOURCE_DIR}/lib/duktape.lib)
set_target_properties(${PROJECT_NAME} PROPERTIES IMPORTED_LOCATION_RELEASE ${CMAKE_CURRENT_SOURCE_DIR}/bin/duktape.dll)
set_target_properties(${PROJECT_NAME} PROPERTIES IMPORTED_LOCATION_RELEASE ${CMAKE_CURRENT_SOURCE_DIR}/lib/duktape.lib)
#target_link_libraries(${PROJECT_NAME} LINK_PUBLIC "duktape.lib")
#add_custom_target(${PROJECT_NAME}_Export MODULE)
#add_dependencies(${PROJECT_NAME} duktape)
#export(PACKAGE ${PROJECT_NAME})
#install(TARGETS ${PROJECT_NAME}
# #EXPORT ${PROJECT_NAME}_Targets
# RUNTIME DESTINATION "${EXECUTABLE_OUTPUT_PATH}"
# ARCHIVE DESTINATION "${LIBRARY_OUTPUT_PATH}"
# LIBRARY DESTINATION "${LIBRARY_OUTPUT_PATH}"
# PUBLIC_HEADER DESTINATION "${INSTALL_INCLUDE_DIR}/${PROJECT_NAME}/include")
#install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/bin/duktape.dll DESTINATION "${EXECUTABLE_OUTPUT_PATH}")
#install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/lib/duktape.lib DESTINATION "${LIBRARY_OUTPUT_PATH}")
#add_custom_command(TARGET ${PROJECT_NAME}
# PRE_LINK
# COMMAND copy ${CMAKE_CURRENT_SOURCE_DIR}/bin/duktape.dll "${EXECUTABLE_OUTPUT_PATH}"
# COMMAND copy ${CMAKE_CURRENT_SOURCE_DIR}/lib/duktape.lib "${LIBRARY_OUTPUT_PATH}"
# )
#add_custom_command(OUTPUT duktape.dll
# COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/bin/duktape.dll ${EXECUTABLE_OUTPUT_PATH}/duktape.dll
# COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/bin/duktape.dll ${EXECUTABLE_OUTPUT_PATH}/duktape.dll
# COMMAND "copy ${CMAKE_CURRENT_SOURCE_DIR}/lib/duktape.lib ${LIBRARY_OUTPUT_PATH}"
# )
So after 2 days wasting time with CMake and its crashes... i just realized that i'm most propably 90% fast, if i would have write the build files manually...
A solution would be nice
Command flow install(TARGETS) installs only targets built within project. It doesn't install imported targets. See, e.g., this bugreport.
For install imported libraries you may use install(FILES) command flow:
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/bin/duktape.dll
DESTINATION <...>)
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/bin/duktape.lib
DESTINATION <...>)
(In your code you install into CMAKE_RUNTIME_OUTPUT_DIRECTORY and similar dirs, which refers to build tree. Never install under build tree!)