I use library Assimp from imported target assimp::assimp in my project:
find_package(assimp REQUIRED 5)
target_link_libraries(${PROJECT_NAME} PUBLIC assimp::assimp)
During link stage of build of the project in Debug configuration I get an error:
src/renderer/CMakeFiles/renderer.dir/build.make:256: *** target pattern contains no '%'. Stop.
The cause of the error is that (on Archlinux) I have no /usr/lib/cmake/assimp-5.0/assimpTargets-debug.cmake and corresponding line in /usr/lib/cmake/assimp-5.0/assimpTargets.cmake. Property IMPORTED_CONFIGURATIONS of assimp::assimp target have only RELEASE value and there is no IMPORTED_LOCATION_DEBUG property, just IMPORTED_LOCATION_RELEASE.
To fix the problem it is needed to add:
set_target_properties(assimp::assimp PROPERTIES MAP_IMPORTED_CONFIG_DEBUG Release)
Right after find_package.
Related
I have an IMPORTED target which comes from a config package generated by conan. Since conan creates packages for the build type specified in the build_type of the profile, I have added CMAKE_MAP_IMPORTED_CONFIG_DEBUG to Release, so that even if I compile a Debug build of my project, I can still use Config files generated with conan using a Release profile.
This works fine for all the targets in my project. include directories are set correctly, libraries link correctly. except for one case:
I have an INTERFACE target which I use to use only the include directories of an IMPORTED target if one option is set, or use the whole target.
add_library(deTracing INTERFACE)
# Get include directories of Tracy::TracyClient target
get_target_property(TRACY_INCLUDE_DIRECTORIES Tracy::TracyClient INTERFACE_INCLUDE_DIRECTORIES)
# Include the directories unconditionally
target_include_directories(deTracing INTERFACE ${TRACY_INCLUDE_DIRECTORIES})
# Some debug stuff
message(status ${TRACY_INCLUDE_DIRECTORIES})
add_custom_target(genexdebug COMMAND ${CMAKE_COMMAND} -E echo "${TRACY_INCLUDE_DIRECTORIES}")
# If ENABLE_PROFILING is set, link to the library
if(ENABLE_PROFILING)
target_link_libraries(deTracing INTERFACE Tracy::TracyClient)
target_compile_definitions(deTracing INTERFACE ENABLE_PROFILING)
endif()
The issue is that TRACY_INCLUDE_DIRECTORIES is a generator expression with this content
$<$<CONFIG:Release>:/home/seddi/.conan/data/tracy/0.9/_/_/package/913e5b8c3a7b64b23fdaa63b58e3915a742a1112/include>, which is what I can expect, it just contains the include directory for the release config.
But when this expression is evaluated in a Debug build, it just collapses to an empty string, even though I have set the CMAKE_MAP_IMPORTED_CONFIG_DEBUG to Release, so it doesn't set any include directories.
I am out of ideas of how I set the correct INCLUDE_DIRECTORIES to deTracing target.
Edit:
According to CMake, the MAP_IMPORTED_CONFIG_ property is followed when evaluating properties of IMPORTED targets. I have modified deTracing to be an IMPORTED target, yet still doesn't work.
add_library(deTracing INTERFACE IMPORTED)
get_target_property(TRACY_INCLUDE_DIRECTORIES Tracy::TracyClient INTERFACE_INCLUDE_DIRECTORIES)
set_property(
TARGET deTracing
PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${TRACY_INCLUDE_DIRECTORIES}
APPEND) # ${TRACY_INCLUDE_DIRECTORIES})
get_target_property(deTracing_INCLUDE_DIRECTORIES deTracing INTERFACE_INCLUDE_DIRECTORIES)
message("deTracing INCLUDE_DIRECTORIES: ${deTracing_INCLUDE_DIRECTORIES}")
add_library(TestTarget INTERFACE)
target_link_libraries(TestTarget INTERFACE deTracing)
get_target_property(TestTarget_INCLUDE_DIRECTORIES TestTarget INTERFACE_INCLUDE_DIRECTORIES)
message("TestTarget INCLUDE DIRECTORIES: ${TestTarget_INCLUDE_DIRECTORIES}")
This snippet produces the following output
[cmake] deTracing INCLUDE_DIRECTORIES: $<$<CONFIG:Release>:/home/seddi/.conan/data/tracy/0.9/_/_/package/913e5b8c3a7b64b23fdaa63b58e3915a742a1112/include>
[cmake] TestTarget INCLUDE DIRECTORIES: TestTarget_INCLUDE_DIRECTORIES-NOTFOUND
which shows that deTracing is able to set the correct INCLUDE_DIRECTORIES for the Release config, but then is unable to set them on TestTarget, even though deTracing is an IMPORTED target.
I would like to use the Antlr framework in a project. I'm using CMake to build the project.
I would like to use the SHARED library version of Antlr, not the STATIC one. Its CMake file contains targets for both.
Antlr's github site explicity tells me to use the following code:
find_package(antlr4-runtime REQUIRED)
# add runtime include directories on this project.
include_directories( ${ANTLR4_INCLUDE_DIR} )
# add runtime to project dependencies
add_dependencies( Parsertest antlr4_shared )
# add runtime to project link libraries
target_link_libraries( Parsertest PRIVATE
antlr4_shared)
(another target, antlr4_static, exists, but shouldn´t be used.)
I copied it exactly like this and am getting the following error:
CMake Error at /usr/lib64/cmake/antlr4-runtime/antlr4-targets.cmake:82 (message):
The imported target "antlr4_static" references the file
"/usr/lib/libantlr4-runtime.a"
but this file does not exist.
I dont have the static library installed in my system as I have no intention of using it. Still, how do I make CMake stop looking for the wrong target in the first place? I use it nowhere in my CMakeLists.txt file and am puzzled by this behavior.
I recently started fixing some broken CMake-based build.
The project relies on a pre-built library (think .lib & .dll file).
The dependency is treated as an imported target; i.e. like this:
add_library(the_dependency SHARED IMPORTED GLOBAL)
set_target_properties(
the_dependency
PROPERTIES
IMPORTED_IMPLIB "definitely_correct_path/the_dependency.lib"
)
Building the project using the Visual Studio Generator works fine. However, using Ninja breaks the build leaving me with this error:
ninja: error: 'the_dependency.lib', needed by 'awesome/target', missing and no known rule to make it
Pretty much the same goes for NMake:
NMAKE : fatal error U1073: don't know how to make 'the_dependency.lib'
What I tried:
I defined the IMPORTED_LOCATION property additionally.
I checked the paths and they're definitely correct.
Also, peaking into the generated build files (i.e. build.ninja), it provides a rule for "generating" the DLL, but none for the LIB file.
Is there something I am missing?
Have a look at
-DENABLE_EXPORTS=TRUE
https://cmake.org/cmake/help/latest/prop_tgt/ENABLE_EXPORTS.html#prop_tgt:ENABLE_EXPORTS
In my project I'm using protobuf 3.5. I need at least the debug and the RelWithDebugInfo configurations. To be able to build the project with protobuf debug libraries led to some problems alone:
I needed to build the protobuf libraries from source using both the release and the debug target since the _ITERATOR_DEBUG_LEVEL of my libraries (= 2) didn't match the level of the protobuf libraries (= 0). After building the debug libraries as well as the release libraries, compiling in debug configuration was possible.
Now, after changing back to RelWithDebugInfo I get the same error again, but now just the opposite: The _ITERATOR_DEBUG_LEVEL of my libraries is 0 and the level of the used protobuf libraries is 2.
When checking the linker configuration, I can see that my libraries are linked against the libprotobufd.lib. This makes sense since I've read somewhere that everything which is not Release will use the debug libraries, if available. And this leads to my problem:
I won't build my libraries in Release during development. It's most of the time RelWithDebugInfo. But the _ITERATOR_DEBUG_LEVEL for this configuration is obviously set to 0 (because it is a release configuration with additional information). But CMake then links against protobuf's debug libraries which are not compatible with the rest.
I'm now looking for a possibility to tell CMake to not use the debug version of the libraries but the release version instead without changing the CMake scripts of protobuf itself.
Normally my way to go would be to link different libraries depending on the actual build configuration. But unfortunately, the protobuf CMake configuration tries to handle this by itself.
# Load information for each installed configuration.
get_filename_component(_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH)
file(GLOB CONFIG_FILES "${_DIR}/protobuf-targets-*.cmake")
foreach(f ${CONFIG_FILES})
include(${f})
endforeach()
whilst the imported target is overwritten selected depending on the actual configuration:
protobuf-targets-release.cmake:
# Import target "protobuf::libprotobuf-lite" for configuration "Release"
set_property(TARGET protobuf::libprotobuf-lite APPEND PROPERTY IMPORTED_CONFIGURATIONS RELEASE)
set_target_properties(protobuf::libprotobuf-lite PROPERTIES
IMPORTED_LINK_INTERFACE_LANGUAGES_RELEASE "CXX"
IMPORTED_LOCATION_RELEASE "${_IMPORT_PREFIX}/lib/libprotobuf-lite.lib"
)
protobuf-targets-debug.cmake:
# Import target "protobuf::libprotobuf-lite" for configuration "Debug"
set_property(TARGET protobuf::libprotobuf-lite APPEND PROPERTY IMPORTED_CONFIGURATIONS DEBUG)
set_target_properties(protobuf::libprotobuf-lite PROPERTIES
IMPORTED_LINK_INTERFACE_LANGUAGES_DEBUG "CXX"
IMPORTED_LOCATION_DEBUG "${_IMPORT_PREFIX}/lib/libprotobuf-lited.lib"
)
whereas the linking in my CMakeLists.txt looks like this:
target_link_libraries(${PROJECT_NAME} PRIVATE
protobuf::libprotobuf
protobuf::libprotoc
)
I don't see any possibility here to specify the desired library. Normally I'd say I would specify it somehow like this:
target_link_libraries(MyEXE
debug protobuf::libprotobufd optimized protobuf::libprotobuf
debug protobuf::libprotocd optimized protobuf::libprotoc)
or wrap some fancy if-condition for the different build configurations around it. But due to protobuf effectively overwriting the target, I don't know how to extract the correct library for each build.
Any ideas?
I'm now looking for a possibility to tell CMake to not use the debug version of the libraries but the release version instead
Variables CMAKE_MAP_IMPORTED_CONFIG_ are intended for resolve exactly that problem:
# When build your project in RelWithDebugInfo configuration,
# try to use Release configuration of the *IMPORTED* libraries.
# If some IMPORTED library has no Release configuration, fallback to Debug one.
set(CMAKE_MAP_IMPORTED_CONFIG_RELWITHDEBUGINFO Release Debug)
# Imported targets set with given call will be aware of the variable's set above
find_package(Protobuf REQUIRED)
# Simply link with an IMPORTED library.
target_link_libraries(MyExe protobuf::libprotobuf)
If you want to use Release configuration only from the specific IMPORTED libraries, but not all, you may set corresponded properties for these specific libraries:
# Firstly, create needed IMPORTED target.
find_package(Protobuf REQUIRED)
# Then adjust its properties.
# While the target is created by others, given property is specifically
# designed to be set in *your project*.
set_property(TARGET protobuf::libprotobuf PROPERTY MAP_IMPORTED_CONFIG_RELWITHDEBUGINFO Release Debug)
# Simply link with an IMPORTED library.
target_link_libraries(MyExe protobuf::libprotobuf)
I am specifying a shared library build from source files in my CMakeLists.txt file like so:
# Library setup
file(GLOB_RECURSE SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/Source/*.cpp)
file(GLOB_RECURSE HEADERS ${CMAKE_CURRENT_SOURCE_DIR}/Source/*.h)
Inside the source directories contain all my .h and .cpp files required to build my shared library. So I then do something like this:
add_library(mylibrary SHARED ${SOURCES} ${HEADERS} )
I also link a bunch of other .libs with mylibrary later on as well (Could there be a clashing issue?). The problem arises when I try to build mylibrary. I receive linking errors such as:
Severity Code Description Project File Line Suppression State
Error LNK2001 unresolved external symbol __imp_cosf mylibrary ***.obj 1
even though the symbol is defined in my source files that I have included. I am not exactly sure what to do in order to properly let my project find those symbols. The funny thing is is that when I build as a static library it is fine. However, when I try to build as a dynamic library, these errors appear.
So, I'm not exactly sure why this worked. But there was a conflict warning between linking to MSVRCT and libcmt. It said something like this in the output log:
Resolving LNK4098: defaultlib 'MSVCRT' conflicts with ...
This is because libcmt is a static library for release build and uses \MT flags. MSVRCT is a release DLL version and compiled with \MD flag. Because of this conflict, I had to change my compiler flags to be:
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /MT")
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /MTd")
Then the symbols were able to be found. If anyone has any comments/corrections to why this worked please add.