How to instruct CMake to use external pre-built libraries - cmake

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

CMake - How propage multiple Dll copy with TARGET_RUNTIME_DLLS when using INTERFACE library to group that Dll

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?

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

Cmake linker error with shared libraries

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

Unifying CMake's FIND_PACKAGE

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.

Transitively require other imported library's interface from imported library

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.