I'm struggling how to find a way to say to CMake to include external prebuilt libraries... It's driving me insane.
It's understatement that I'm new to CMake. I just want that MinGW linker add two external .lib files to link list... I'm pulling my hair at this point.
This is my CMakeLists.txt file:
cmake_minimum_required(VERSION 3.9)
project(opengltest C CXX)
set(CMAKE_CXX_STANDARD 11)
file(GLOB
TestSRC
"src/*.h"
"src/*.cpp"
"src/*.c"
)
add_executable(opengltest ${TestSRC})
include_directories(
3rdparty/glew/include
3rdparty/glfw/include
)
link_directories(
${PROJECT_SOURCE_DIR}/3rdparty/glew/lib/Release/x64/
${PROJECT_SOURCE_DIR}/3rdparty/glfw/build/src/Debug/
)
target_link_libraries(${PROJECT_NAME} glew32s glfw3)
Linker says it cannot find glew32s and glfw3.
EDIT: I think I've found the solution:
...
add_library(glew32s STATIC IMPORTED)
set_property(TARGET glew32s PROPERTY IMPORTED_LOCATION ${PROJECT_SOURCE_DIR}/libs/glew32s.lib)
add_library(glfw3 STATIC IMPORTED)
set_property(TARGET glfw3 PROPERTY IMPORTED_LOCATION ${PROJECT_SOURCE_DIR}/libs/glfw3.lib)
target_link_libraries(${PROJECT_NAME} glew32s glfw3)
I've moved all my .lib files to one folder and used add_library to include them.
...
add_library(glew32s STATIC IMPORTED)
set_property(TARGET glew32s PROPERTY IMPORTED_LOCATION ${PROJECT_SOURCE_DIR}/libs/glew32s.lib)
add_library(glfw3 STATIC IMPORTED)
set_property(TARGET glfw3 PROPERTY IMPORTED_LOCATION ${PROJECT_SOURCE_DIR}/libs/glfw3.lib)
target_link_libraries(${PROJECT_NAME} glew32s glfw3)
After that linker was able to find lib files.
Related
I have a library INTERFACE which reference multiples IMPORTED library, one for each Dll/lib.
The INTERFACE library is here to group that Dlls/sublibraries in one lib.
When I'm using TARGET_RUNTIME_DLLS to copy all depending Dlls, the Dlls are not copy if declare through an INTERFACE library.
# OpenSSL eay
add_library(openssl_eay SHARED IMPORTED)
set_property(TARGET openssl_eay PROPERTY IMPORTED_LOCATION "${CMAKE_SOURCE_DIR}/Libs/OpenSSL/Bin/libeay32.dll")
set_property(TARGET openssl_eay PROPERTY IMPORTED_IMPLIB "${CMAKE_SOURCE_DIR}/Libs/OpenSSL/Bin/libeay32.lib")
# OpenSSL ssleay
add_library(openssl_ssleay SHARED IMPORTED)
set_property(TARGET openssl_ssleay PROPERTY IMPORTED_LOCATION "${CMAKE_SOURCE_DIR}/Libs/OpenSSL/Bin/ssleay32.dll")
set_property(TARGET openssl_ssleay PROPERTY IMPORTED_IMPLIB "${CMAKE_SOURCE_DIR}/Libs/OpenSSL/lib/Bin/ssleay32.lib")
# OpenSSL
add_library(openssl INTERFACE IMPORTED)
target_link_libraries(openssl INTERFACE openssl_eay openssl_ssleay)
# Foo
add_library(Foo SHARED IMPORTED)
set_property(TARGET Foo PROPERTY IMPORTED_LOCATION "${CMAKE_SOURCE_DIR}/Libs/Foo/Bin/Foo.dll")
set_property(TARGET Foo PROPERTY IMPORTED_IMPLIB "${CMAKE_SOURCE_DIR}/Libs/Foo/Bin/Foo.lib")
add_executable(MyExecutable Main.cpp)
target_link_libraries(MyExecutable PRIVATE openssl)
add_custom_command(TARGET MyExecutable POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_RUNTIME_DLLS:MyExecutable> $<TARGET_FILE_DIR:MyExecutable>
COMMAND_EXPAND_LISTS
)
With that configuration, CMake only copy Foo.dll next to the executable, but not libeay32.dll and ssleay32.dll.
I try to declare add_library(openssl INTERFACE) without IMPORTED, but same result/problem.
How I can modified openssl library declaration to have the dependant imported Dlls copy?
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")
Im having an error on a chain linking, I've read lots of post but can't find a solution.
I build 3 libraries, in separated folders:
lib_1 as shared without dependencies
lib_2 as shared requiring lib_1 (build without problems)
lib_3 as shared that requires both lib_1 & lib_2
Here are the simplified CMakelists.txt (path have been simplified & triple-checked and mines are ok)
project (lib_1)
set (CMAKE_CXX_STANDARD 11)
set(CMAKE_BUILD_TYPE Release)
include_directories( lib_1/include/path/)
add_library(lib_1 SHARED lib_1/source/path)
====================================
cmake_minimum_required(VERSION 2.8)
project (lib_2)
set (CMAKE_CXX_STANDARD 11)
set(CMAKE_BUILD_TYPE Release)
include_directories( lib_2/include/path/)
add_library(lib_2 SHARED lib_2/source/path)
add_library(lib_1 SHARED IMPORTED)
set_property(TARGET lib_1 PROPERTY IMPORTED_LOCATION "lib_1/path/file.dylib")
=============
cmake_minimum_required(VERSION 2.8)
project (lib_3)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_BUILD_TYPE Release)
include_directories( lib_3/include/path/)
add_library(lib_3 SHARED lib_3/sources/path)
add_library(lib_1 SHARED IMPORTED)
set_property(TARGET lib_1 PROPERTY IMPORTED_LOCATION "/lib_1/path/file.dylib")
add_library(lib_2 SHARED IMPORTED)
set_property(TARGET lib_2 PROPERTY IMPORTED_LOCATION "/lib_2/path/file.dylib")
Funny thing is I think that add_library & set_property of lib_3 do nothing as removing the line doesn't change the error, i.e. I'm not doing what I should...but I've no idea anymore.
(Side note code runs smoothly if I build all files at once, but I'm trying my hands at shared libraries)
Error for reference:
[100%] Linking CXX shared library lib_3.dylib
Undefined symbols for architecture x86_64:
"LIB_1 function", referenced from:
in lib_3.cpp.o
[...]
Followed by all lib_1 & lib_2 functions marker as undefined
Do you know a trick to get a unified output terminology when getting include and library paths from CMake's FIND_PACKAGE?
Sometimes it's FOO_INCLUDE. Sometimes it's FOO_INCLUDE_PATH. Etc.
For example, I would like to find a way to ensure that FOO_INCLUDE and FOO_LIB be always defined when FOO_FOUND is set to TRUE after a call to FIND_PACKAGE.
Turning my comment into an answer
To avoid the need to know the include path, library, etc. dependencies and their variable notations modern find_package's implementation do provide IMPORTED targets like Foo::Foo. But this is - as #Tsyvarev has commented - far from unified through all of CMake's find modules.
So generalizing the CMake's Sample Find Module implementation you could unify your find_package() calls with an overwritten find_package() macro version like the following:
cmake_minimum_required(VERSION 3.2)
project(UnifiedFindPackage)
macro(unify_vars _result)
set(${_result} "")
foreach(_i IN ITEMS ${ARGN})
if (${_i})
list(APPEND ${_result} "${${_i}}")
endif()
endforeach()
endmacro()
macro(find_package _name)
_find_package(${_name} ${ARGN})
if (${_name}_FOUND AND NOT TARGET ${_name}::${_name})
add_library(${_name}::${_name} STATIC IMPORTED GLOBAL)
unify_vars(_var ${_name}_LIBRARY ${_name}_LIB)
if (_var)
set_target_properties(${_name}::${_name} PROPERTIES IMPORTED_LOCATION "${_var}")
endif()
if (${_name}_LIBRARY_RELEASE)
set_property(TARGET ${_name}::${_name} APPEND PROPERTY IMPORTED_CONFIGURATIONS RELEASE)
set_target_properties(${_name}::${_name} PROPERTIES IMPORTED_LOCATION_RELEASE "${${_name}_LIBRARY_RELEASE}")
endif()
if (${_name}_LIBRARY_DEBUG)
set_property(TARGET ${_name}::${_name} APPEND PROPERTY IMPORTED_CONFIGURATIONS DEBUG)
set_target_properties(${_name}::${_name} PROPERTIES IMPORTED_LOCATION_DEBUG "${${_name}_LIBRARY_DEBUG}")
endif()
if (${_name}_LIBRARIES)
set_property(TARGET ${_name}::${_name} APPEND PROPERTY INTERFACE_LINK_LIBRARIES "${${_name}_LIBRARIES}")
endif()
unify_vars(_var ${_name}_INCLUDE_DIRS ${_name}_INCLUDE_PATH)
if (_var)
set_property(TARGET ${_name}::${_name} APPEND PROPERTY INTERFACE_INCLUDE_DIRECTORIES "${_var}")
endif()
unify_vars(_var ${_name}_COMPILE_FLAGS ${_name}_DEFINITIONS)
if (_var)
set_property(TARGET ${_name}::${_name} APPEND PROPERTY INTERFACE_COMPILE_OPTIONS "${_var}")
endif()
endif()
endmacro()
find_package(MPI REQUIRED)
add_executable(${PROJECT_NAME} main.c)
target_link_libraries(${PROJECT_NAME} MPI::MPI)
This should only demonstrate a possible unification and could be extended on a need-by basis.
Edit: Turning this into an community wiki answer. Please feel free to contribute.
The code was tested in this example with MPI find module results.
CMake 3.5
I have an existing external library, which I have made an IMPORTED library in my CMakeLists.txt:
find_path(
FOO_INCLUDE_DIR NAMES foo.h
PATHS "${FOO_ROOT}"
NO_DEFAULT_PATH
PATH_SUFFIXES include/foo
)
find_library(
FOO_LIBRARY NAMES foo
PATHS "${FOO_ROOT}"
PATH_SUFFIXES lib
)
mark_as_advanced(FOO_INCLUDE_DIR FOO_LIBRARY)
find_package_handle_standard_args(
FOO REQUIRED_VARS
FOO_INCLUDE_DIR
FOO_LIBRARY
)
add_library(Foo::Foo SHARED IMPORTED)
set_property(TARGET Foo::Foo
PROPERTY INTERFACE_INCLUDE_DIRECTORIES
"${FOO_INCLUDE_DIR}" "${BAR_INCLUDE_DIR}"
"${Boost_INCLUDE_DIRS}" "${BAZ_INCLUDE_DIR}"
)
set_property(TARGET Foo::Foo
PROPERTY IMPORTED_LOCATION
"${FOO_LIBRARY}"
)
set_property(TARGET Foo::Foo
PROPERTY INTERFACE_LINK_LIBRARIES
"${Boost_LIBRARIES}" "${BAR_LIBRARY}" "${BAZ_LIBRARIES}"
)
Programs that link with this particular library need thread support. Adding thread support to something is fairly straightforward:
set(THREADS_PREFER_PTHREAD_FLAG on)
include(FindThreads)
...
target_link_libraries(something PUBLIC Threads::Threads)
I would like anything that links against Foo::Foo to automatically include Threads::Threads. But you can't use target_link_libraries() on an IMPORTED library. So how do I transitively require Threads::Threads from Foo::Foo?
I managed to work around this by doing the following, but it depended on me checking to see what properties FindThreads sets on Threads::Threads. Is there a better way?
set_property(TARGET Foo::Foo
PROPERTY INTERFACE_LINK_LIBRARIES
"${Boost_LIBRARIES}" "${BAR_LIBRARY}" "${BAZ_LIBRARIES}"
$<TARGET_PROPERTY:Threads::Threads,INTERFACE_LINK_LIBRARIES>
)
set_property(TARGET Foo::Foo
PROPERTY INTERFACE_COMPILE_OPTIONS
$<TARGET_PROPERTY:Threads::Threads,INTERFACE_COMPILE_OPTIONS>
)
It turns out the answer was quite simple. I simple needed to add Threads::Threads to the INTERFACE_LINK_LIBRARIES property of Foo::Foo. I have no idea why I had determined that would not work the first time around.