cmake add external library - c++

I would like to add a dependency to a target. This dependency is a precompiled lib. I would like to be able to get a external dependency just by specifing a name like add_dep(libName) in my CMakeLists.txt. The add_dep function should be reusable for different libraries.
I couldn't find any way to do this, only for libs which are compiled during build
how would I pass the target name in a generic form here?
would be fine, but the "consumer" shouldn't have to add inc/lib dirs etc.

Based on Some programmer dude:
In the dir of the external lib CMakeList.txt:
find_library(lib libName dir/to)
add_library(libName SHARED IMPORTED GLOBAL) # GLOBAL -> if outside src tree
set_property(TARGET libName PROPERTY IMPORTED_LOCATION ${lib})
set_property(TARGET libName APPEND PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${CMAKE_CURRENT_SOURCE_DIR}/include)
in the "root" CMakeList.txt:
add_subdirectory("$ENV{COMMON_ROOT}/libs/libName" "$ENV{COMMON_ROOT}/libs/libName") # usage for out of src ref
add target_link_libraries(target libName) to the CMakeLists.txt who needs it.

Related

How do you link precompiled libraries in CMake?

# file(COPY ${CMAKE_SOURCE_DIR}/libs/glew32.lib DESTINATION ${PROJECT_BINARY_DIR}/libs)
# file(COPY ${CMAKE_SOURCE_DIR}/libs/libglfw3dll.a DESTINATION ${PROJECT_BINARY_DIR}/libs)
add_executable(${PROJECT_NAME} main.cpp)
# libs/glew32.lib
# libs/libglfw3dll.a
# "main.cpp"
# )
target_link_libraries(${PROJECT_NAME}
libs/glew32.lib
libs/libglfw3dll.a
)
I've tried doing every option here but they end up causing linking errors. I tried both compiling from src and using every available format glfw and glew provided.
I usually create a CMake target first to import the prebuilt/precompiled library, then use target_link_libraries like y ou normally link to a CMake library target. The benefit is you can control the dependency being a PRIVATE dependency or a PUBLIC one.
project(YourCoolProject)
# Import a prebuilt library to a CMake target
add_library(Foo SHARED IMPORTED)
set_target_properties(Foo PROPERTIES
IMPORTED_LOCATION_DEBUG "/absolute-path/to/prebuilt-debug-library"
IMPORTED_LOCATION_RELEASE "/absolute-path/to/prebuilt-release-library"
IMPORTED_LOCATION_RELWITHDEBINFO "/absolute-path/to/prebuilt-relwithdebinfo-library"
INTERFACE_INCLUDE_DIRECTORIES "/absolute-path/to/include-dir"
)
add_executable(${PROJECT_NAME} main.cpp)
target_link_libraries(${PROJECT_NAME} PRIVATE Foo)
Notes:
The choice of IMPORTED_LOCATION_<CONFIG> depends on the build type you provide to CMake (cmake -DCMAKE_BUILD_TYPE=<CONFIG> ...).
In order to replace the absolute path, you can use find_library to utilize CMake to find your library and store it in a variable and use find_path to find the include directory.
You probably need to use target_link_directories() as well to tell the compiler where to find the libraries:
target_link_directories(${PROJECT_NAME} ${PROJECT_BINARY_DIR}/libs/)

How to make CMAKE find specific version of lib curl on OSX?

Question is: How do I get CMAKE to set/make the CURL_INCLUDE_DIR be "/usr/local/Cellar/curl/7.75.0/include/"?
No matter what I do, CMAKE only finds the Xcode lib version/location.
My CMAKE file contains:
set(CURL_ROOT_DIR /usr/local/Cellar/curl/7.75.0/include/)
find_package(curl REQUIRED)
message(STATUS ">>> CURL Dir Found: " ${CURL_INCLUDE_DIR})
No matter what I've tried, the above CMAKE code will result in a "CURL_INCLUDE_DIR" of
"/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.13.sdk/usr/include
Note, utilizing "include(findcurl)" instead of "find_package(curl REQUIRED)" gives same result.
I've resorted to adding
set(CMAKE_CXX_FLAGS "-I/usr/local/Cellar/curl/7.57.0/include
-L/usr/local/Cellar/curl/7.57.0/lib")
to get CMAKE to actually utilize the lib version/location that I want. Is there a better way that I'm failing to figure out?
The cmake FindCURL module (at least in the version I have, 3.5.1) does not make reference to CURL_ROOT_DIR anywhere, so I don't believe setting that variable will have any effect.
In fact the FindCURL module is really quite basic and doesn't offer any means for customising where to look, which means it will be looking only in "standard" paths (eg /usr/lib, /usr/local/lib etc)
You can, however, use find_library which takes a PATHS argument.
set(CURL_PATH "/usr/local/Cellar/curl/7.75.0")
find_library(
LIB_CURL
NAMES
curl
PATHS
${CURL_PATH}/lib)
At this point you will have a variable ${LIB_CURL} which points to the location of libcurl
Link against the library and set the include path:
You can then just link against ${LIB_CURL} directly, and manually specify the include path for your target too, such as:
add_executable(
foo
main.cpp)
target_link_libraries(
foo
${LIB_CURL})
target_include_directories(
foo
SYSTEM
PRIVATE "${CURL_PATH}/include")
IMPORTED library target:
Another option, if you want to be fancy, is to create an IMPORTED library target using ${LIB_CURL}, and set the INTERFACE_INCLUDE_DIRECTORIES on that target, so consumers get the include path set automatically.
add_library(
libcurl
IMPORTED)
set_target_properties(
libcurl
PROPERTIES
IMPORTED_LOCATION "${LIB_CURL}")
set_target_properties(
libcurl
PROPERTIES
INTERFACE_INCLUDE_DIRECTORIES "${CURL_PATH}/include")
Now you will just be able to link against target libcurl directly, and your app will automatically have its include paths updated
add_executable(
foo
main.cpp)
target_link_libraries(
foo
libcurl)

cmakelists importing external library leads to invalid or corrupted dll

I cannot figure out why the library cannot be linked into my project, any help will be appreciated.
Background: The external library provides a list of header files and library files and are put in a directory named "dll", files including "Elveflow64.aliases","Elveflow64.dll","Elveflow64.ini","Elveflow64.lib""Elveflow64.h","*.h","lvanlys.dll".
The codes I use in the CMakeLists file are shown as bellow:
SET("LIB_Elveflow_DIR" ${CMAKE_CURRENT_SOURCE_DIR}/dll)
include_directories(${LIB_Elveflow_DIR})
add_library(Elveflow64 SHARED IMPORTED) #${LIB_Elveflow_DIR}//Elveflow64.lib
set_property(TARGET Elveflow64 PROPERTY IMPORTED_LOCATION ${LIB_Elveflow_DIR}/Elveflow64.dll)
set_property(TARGET Elveflow64 PROPERTY IMPORTED_IMPLIB ${LIB_Elveflow_DIR}/Elveflow64.lib)
set_property(TARGET Elveflow64 PROPERTY IMPORTED_LINK_DEPENDENT_LIBRARIES ${LIB_Elveflow_DIR}/lvanlys.dll)
TARGET_LINK_LIBRARIES(${PROJECT_NAME} Elveflow64)
However, when I run the code, The program has unexpectedly finished as Elveflow64.dll is missing.

CMAKE: Linking OpenCV fails when imported

I am trying to import OpenCV into my CMakeLists.txt file. Here's the code I'm using:
find_package(OpenCV 3 REQUIRED)
add_library(opencv SHARED IMPORTED)
set_target_properties(opencv PROPERTIES
INTERFACE_INCLUDE_DIRECTORIES "${OpenCV_INCLUDE_DIRS}"
IMPORTED_LOCATION "${OpenCV_LIBS}")
Later in the cmake file, I create a target that links to opencv, like so:
add_executable(sample "src/sample.cpp")
target_link_libraries(sample opencv)
However, this fails to build. I happen to be using Ninja, but it fails with Make too.
Here is the error I am getting when I try to build with Ninja:
ninja: error: stat(opencv_viz;opencv_videostab;opencv_videoio;opencv_video;opencv_superres;opencv_stitching;opencv_shape;opencv_photo;opencv_objdetect;opencv_ml;opencv_imgproc;opencv_imgcodecs;opencv_highgui;opencv_flann;opencv_features2d;opencv_cudev;opencv_cudawarping;opencv_cudastereo;opencv_cudaoptflow;opencv_cudaobjdetect;opencv_cudalegacy;opencv_cudaimgproc;opencv_cudafilters;opencv_cudafeatures2d;opencv_cudacodec;opencv_cudabgsegm;opencv_cudaarithm;opencv_core;opencv_calib3d): File name too long
Clearly the value of ${OpenCV_LIBS} is a list of values, and that list is getting passed as one long string instead of being split up and linked as individual args to the compiler.
I have verified that other libraries fail too if the IMPORTED_LOCATION is a list of values (separated by semi-colon) instead of just being a single path to a library.
What am I doing wrong?
The problem is that a shared imported library will be looking for one file to link against.
To solve your problem, I would use an interface library instead and set its dependencies:
find_package(OpenCV 3 REQUIRED)
add_library(opencv INTERFACE )
target_include_directories(opencv INTERFACE "${OpenCV_INCLUDE_DIRS}")
target_link_libraries(opencv INTERFACE "${OpenCV_LIBS}")
The target_include_directories may even not be necessary depending on your CMake version.
oLen's answer will work, but then you lose the ability to mark the library as IMPORTED.
A better way to accomplish what I was trying to do it to set the INTERFACE_LINK_LIBRARIES property. The library should also be an INTERFACE library instead of SHARED.
So the cmake config to import the target becomes:
find_package(OpenCV 3 REQUIRED)
add_library(opencv INTERFACE IMPORTED)
set_target_properties(opencv PROPERTIES
INTERFACE_INCLUDE_DIRECTORIES "${OpenCV_INCLUDE_DIRS}"
INTERFACE_LINK_LIBRARIES "${OpenCV_LIBS}")

Unable to include external previous built .a libraries in cmake

I have a libgarithm.a library previously compiled and have a header file garith.h how could i import it in my cmake project . I have included header files from
include_directories("/home/gaurav/Desktop/garith-lib/include")
but unable to link libraries and it is giving a comile time error
--- undefined reference to `multi(int, int)' the function in my library
You should create an imported target for your library and then use target_link_libraries:
add_library(garithm STATIC IMPORTED)
set_property(TARGET garithm PROPERTY IMPORTED_LOCATION
/path/to/libgarithm.a
)
set_property(TARGET garithm PROPERTY INTERFACE_INCLUDE_DIRECTORIES
/home/gaurav/Desktop/garith-lib/include
)
...
add_executable(foo main.cpp)
target_link_libraries(foo garithm)
Include directories are declared on the imported target as well so you don't have to call include_directories
EDIT: target_include_directoriesdoesn't work with imported targets, set the property INTERFACE_INCLUDE_DIRECTORIES instead
Starting with CMake 3.12.1, target_include_directories as well as other syntactic sugar for normal targets is also supported with imported targets.
For those writing cmake files with these statements, please do add cmake_minimum_required(3.12)
If you are getting errors such when compiling a particular third party library, check the cmake --version