Create external module import files [duplicate] - cmake

I've a strange problem with CMake.
I'm importing Curl into my project, so I write for you a simplified summary of my CMakeLists.txt file.
ADD_LIBRARY (libcurl SHARED IMPORTED)
SET_PROPERTY(TARGET libcurl PROPERTY IMPORTED_LOCATION
../lib/libcurl.lib)
When I run CMake it generates the project files for MS VC++ (also for Linux). Then into the project file I find a wrong reference to curl library (libcurl-NOTFOUND)!
If I change my code into static import:
ADD_LIBRARY (libcurl STATIC IMPORTED)
SET_PROPERTY(TARGET libcurl PROPERTY IMPORTED_LOCATION
../lib/libcurl.lib)
I find the right reference to ../lib/libcurl.lib.
Do you have any idea why this happens?
Thank you very much!

For a shared library, the IMPORTED_LOCATION must point to the DLL, not the import lib. See the documentation. You might also want to set the IMPORTED_IMPLIB property.
BTW, CMake also has a find package for Curl; perhaps you could use that?

Related

Use target_link_libraries to libraries not start with lib*

I am trying to link my program(hello) with a special library(/path/abc.so) that not starts with 'lib'.
Here is my CMakeLists.txt
add_executables(hello hello.c)
target_link_libraries(hello /path/abc.so)
It works fine, but is there any other way to avoid this full path(/path/abc.so) things?
I don't want to make symlink of abc.so or modify abc.so itself.
Probably your best option is not to link directly the library, but use imported targets:
You can have your library target as
add_library(ABC SHARED IMPORTED)
set_target_properties(ABC PROPERTIES
IMPORTED_LOCATION path/to/library/abc.so
INTERFACE_INCLUDE_DIRECTORIES path/to/include
)
Then you can link it as a target:
target_link_libraries(hello ABC)
The next step would be to have a library find module, or config module, so you don't define full path in your CMakeLists.txt, but search for the library, or just include a .cmake file with all of the paths.
Have a look HERE and HERE

How can I create a target for an _existing_ library?

In CMake, we can add_library(mylib file1.cpp file2.cpp) and have a mylib.a in the library path get built. We can also target_include_directories(mylib INTERFACE some/directory), which effects targets depending on mylib.
But what if I have a library to begin with, which I will not be compiling. How can I add a target relating to it? That what I add as a dependency, will cause the .a file to be linked against, and for which I can set target_include_directories() ?
Note: I'm asking about CMake 3.x.
CMake provide an alternate signature for libraries that are already compiled:
add_library(
mynamespace::mylib
STATIC # or it could be SHARED
IMPORTED
)
See the official CMake documentation for more details.
with that you'll be able to add properties to the target doing so
set_target_properties(
mynamespace::mylib
PROPERTIES
IMPORTED_LOCATION "path/to/libmylib.a"
)
Little precision here, if you're using a Windows DLL, you must pass the DLL file's path in IMPORTED_LOCATION and set another property IMPORTED_IMPLIB that points to the .lib file, (not very handy).
Note that there is also a equivalent properties per configuration (Debug, and Release), that will need another property to be set (IMPORTED_CONFIGURATION), e.g. IMPORTED_LOCATION_DEBUG.
See also here and here in the documentation.
To avoid missing include files you can also precise the include directory using INTERFACE_INCLUDE_DIRECTORY property
set_target_properties(
mynamespace::mylib
PROPERTIES
INTERFACE_INCLUDE_DIRECTORIES "path/to/mylib/include"
)
With this, upon link declaration using target_link_libraries(), CMake will read information of the imported target and will add include directories implicitly.
Official documentation reference.

Why use add_library({tgt} IMPORTED) versus target_link_libraries( -l {.so | .a})?

What is the purpose of using the statement:
add_library(<tgt> [SHARED|STATIC] IMPORTED)
From what I have found even if you create an imported library target above you still would need to specify the specific location of the actual .so or .a. This would take at least 3 cmake commands to link to an executable and the compiler still would not automatically search through the common include directories on your OS.
Example:
cmake code to link IMPORTED lib
From the CMake documentation I understand there are really 3 ways to link a library that is not built as a target in a subproject of your overall application/library.
CMake target_link_libraries() documentation
Using a CMake package for one of the shipped package scripts.
Using a linker flag:
target_link_libraries(<tgt> [SHARED|STATIC|...] -lncursesw)
Or using the IMPORTED library method (showcased in code at top).
A major difference when using the second method is that it only takes a single line of code and will search through all of your compiler's predefined include directories on you OS. Could anyone help me understand why the add_library() method is used?
Additional Realated SO Posts:
Include directories for IMPORTED libs
CMake imported library behavior
You should use add_library(<tgt> [SHARED|STATIC] IMPORTED) whenever you need to set properties such as dependencies, compile definitions, compile flags etc for <tgt>, and/or by extension, any targets that are linking against <tgt>.
Let's say you have two static libraries; libfoobar.a and libraboof.a, where libfoobar.a requires libraboof.a. Let's also say that these libraries contain some features that are enabled by -DSOME_FEATURE.
add_library(raboof STATIC IMPORTED)
set_target_properties(raboof PROPERTIES
IMPORTED_LOCATION <path-to-libraboof.a>
INTERFACE_COMPILE_DEFINITIONS "SOME_FEATURE"
)
add_library(foobar STATIC IMPORTED)
set_target_properties(foobar PROPERTIES
IMPORTED_LOCATION <path-to-libfoobar.a>
INTERFACE_LINK_LIBRARIES raboof
)
So when you link against libfoobar.a:
add_executable(my_app main.cpp)
target_link_libraries(my_app foobar)
CMake will make sure to link all dependencies in the correct order and will in this case also append -DSOME_FEATURE to the compile flags when you build my_app. Note that since we added libraboof.a as a dependency to libfoobar.a, -DSOME_FEATURE is added to any target that link against libfoobar.a through the transitive property.
If you don't use add_library(<tgt> <SHARED|STATIC> IMPORTED) in a scenario like this, you would have to manage any dependencies and required build options yourself for each target, which is quite error-prone.
This method is also often used in Config-modules for multi-component libraries to manage dependencies between the components.

How do I specify the include directory for an imported shared library using CMake?

I am using cmake version 3.9.1.
I have a third party shared library and header file in my source tree. I am trying to add it as a link target.
All the documentation I can find says that this should work:
test.cpp
#include "ftd2xx.h"
int main(int argc, char **argv)
{
FT_HANDLE handle;
FT_STATUS status = FT_Open(1, &handle);
return 0;
}
CMakeLists.txt
cmake_minimum_required (VERSION 3.6)
project(test_proj CXX)
add_subdirectory(ftdi)
add_executable(mytest test.cpp)
target_link_libraries(mytest ftd2xx)
ftdi/CMakeLists.txt
add_library(ftd2xx SHARED IMPORTED)
set_target_properties(ftd2xx PROPERTIES INTERFACE_INCLUDE_DIRECTORIES ${CMAKE_CURRENT_SOURCE_DIR})
set_target_properties(ftd2xx PROPERTIES IMPORTED_LOCATION ${CMAKE_CURRENT_SOURCE_DIR})
However compiling test.cpp, which includes "ftd2xx.h", complains that it cannot find the header file and the relevant -I<path> entry is missing from the generated makefiles.
If I specify the library as INTERFACE rather than SHARED IMPORTED then the header file is found correctly, but CMake barfs on setting the IMPORTED_LOCATION property.
If I specify the library as INTERFACE rather than SHARED IMPORTED and then use target_link_libraries to point directly to the library file than this works for Windows but not for Linux.
I'd appreciate any help anyone can offer.
The CMake documentation does actually answer this one, but so concisely, and in the middle of a much larger paragraph, that it is easy to miss:
The target name has scope in the directory in which it is created and below, but the GLOBAL option extends visibility.
I am using the target name in a higher level directory, so I need to declare the library as SHARED IMPORTED GLOBAL rather than just SHARED IMPORTED.
Final code is:
add_library(ftd2xx SHARED IMPORTED GLOBAL)
set_target_properties(ftd2xx PROPERTIES INTERFACE_INCLUDE_DIRECTORIES ${CMAKE_CURRENT_SOURCE_DIR})
And then for Windows:
set_target_properties(ftd2xx PROPERTIES IMPORTED_IMPLIB ${CMAKE_CURRENT_SOURCE_DIR}/win32/ftd2xx.lib)
set_target_properties(ftd2xx PROPERTIES IMPORTED_LOCATION ${CMAKE_CURRENT_SOURCE_DIR}/win32/ftd2xx.dll)
And for Linux:
set_target_properties(ftd2xx PROPERTIES IMPORTED_LOCATION ${CMAKE_CURRENT_SOURCE_DIR}/i386/libftd2xx.so)

cmake doesn't support imported libraries?

When I try to import a library using
add_library(libname SHARED IMPORTED)
set_property(TARGET libname PROPERTY IMPORTED_LOCATION /<foldername>/<sub-foldername>/lib")
The cmake shouts :
CMake Warning (dev) at /CMakeLists.txt:28
(target_link_libraries): Cannot specify link libraries for target
"libname" which is not built by this project.
CMake does not support this but it used to work accidentally and is
being allowed for compatibility.
Policy CMP0016 is not set: target_link_libraries() reports error if
only argument is not a target. Run "cmake --help-policy CMP0016"
for policy details. Use the cmake_policy command to set the policy
and suppress this warning. This warning is for project developers.
Use -Wno-dev to suppress it.
If this is true, what is the other best way to include a library somewhere in my build tree into another project.
I have a library setup and another place has executable which will be using the libraries.
Reading through the cmake documentation, it felt like this would be the best way forward but seems its a broken piece which is just being supported.
Cannot specify link libraries for target "libname" which is not built by this project
When you use target_link_libraries to some target you're specifying how to build it,
but imported library is already build. CMake told you that...
Example of linking imported target to executable:
add_library(boo SHARED IMPORTED)
set_target_properties(boo PROPERTIES IMPORTED_LOCATION "/path/to/boo/library")
add_executable(foo foo.cpp)
target_link_libraries(foo boo)
Note: using imported targets
I was getting the same error as navderm when trying to import the Poco C++ libPocoFoundation.so library into my project, and after trying different solutions unsuccessfully, I managed to find one that worked for me:
cmake_minimum_required(VERSION 3.5)
project(MyProject)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
add_library(PocoLib SHARED IMPORTED GLOBAL)
# It's important to specify the full path to the library you want to import
set_target_properties(PocoLib PROPERTIES IMPORTED_LOCATION "/usr/local/lib/Poco_1.7.2/lib/libPocoFoundation.so")
# create my executable
set(EXEC_SOURCE_FILES main.cpp)
add_executable(MyProject ${EXEC_SOURCE_FILES})
target_link_libraries(MyProject PocoLib)