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
Related
# 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/)
I am currently migrating a couple of CodeBlock projects to use CMake and Visual Studio Code. I am facing an issue related to the include directory not being known by the consuming target.
I followed a guide so far as I was not aware of the "modern CMake way" using targets at all until yet. Mainly referring to here: https://rix0r.nl/blog/2015/08/13/cmake-guide/ and the official CMake docs.
There are two libraries (.so). One of them needs to other one to be there (build) when it get's loaded by the application later on.
I am not sure if everything is even intended to work like I assume it to work so I will just continue with the code and the expected result.
Library A (which is needed by Library B) has following CMakeLists
cmake_minimum_required(VERSION 3.0.0)
project(A)
set(SOURCE somesource.c)
include(GNUInstallDirs)
find_package(JNI REQUIRED)
add_library(JNI SHARED IMPORTED)
set_property(TARGET JNI PROPERTY INTERFACE_INCLUDE_DIRECTORIES $ENV{JAVA_HOME}/include $ENV{JAVA_HOME}/include/linux)
set_property(TARGET JNI PROPERTY IMPORTED_LOCATION ${JNI_LIBRARIES})
add_library(${PROJECT_NAME} SHARED ${SOURCE})
target_include_directories(${PROJECT_NAME}
PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include $ENV{JAVA_HOME}/include $ENV{JAVA_HOME}/include/linux>
$<INSTALL_INTERFACE:include>
)
install(DIRECTORY include/ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
install(TARGETS ${PROJECT_NAME} EXPORT ${PROJECT_NAME}Config
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR})
install(EXPORT ${PROJECT_NAME}Config DESTINATION ${CMAKE_INSTALL_PREFIX}/cmake)
Notice I only have one include file which is public and located in "include", so its used by the library itself but should also be part of the install interface
used by the "consuming" target.
Library B (which uses Library A and its header)
cmake_minimum_required(VERSION 3.0)
project(B)
set(SOURCE somesource.c)
add_library(${PROJECT_NAME} SHARED ${SOURCE})
find_package(A REQUIRED)
target_include_directories(${PROJECT_NAME}
PRIVATE ${PROJECT_SOURCE_DIR}
)
So in Library B I assume that I do not need to add the include_directories from Library A again. This is why I actually did the target approach so there is no need to keep track of linker/include dependencies. "find_package" should handle these on it's own right? I do not link neither because it is a shared object, not a static library.
Both libraries use the same CMAKE_INSTALL_PREFIX ofc and library A has been installed (make install). I double-checked on this. In case of using a different prefix or not doing the install, CMake already complains about not finding it.
So considering the issue now:
Within a source file from library B, I am using
#include <libcobjava.h>
resulting in an error when building as the compiler complains about "No such file or directory" Am I missing something? The file is definitely located at
CMAKE_INSTALL_PREFIX/include.
Apart from that as I am still new to CMake: Is this even the way you would do things if you own all the source?
Edit: Some more details on the follow-up issue as discussed in comments. Library A is libcobjava.
First I had the target_include_directories part as following (including the path where jni.h is located in $<INSTALL_INTERFACE:)
target_include_directories(${PROJECT_NAME}
PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include $ENV{JAVA_HOME}/include $ENV{JAVA_HOME}/include/linux>
$<INSTALL_INTERFACE:include $ENV{JAVA_HOME}/include $ENV{JAVA_HOME}/include/linux>
)
results in following error:
[cmake] Configuring done
[cmake] CMake Error in CMakeLists.txt:
[cmake] Target "libcobjava" INTERFACE_INCLUDE_DIRECTORIES property contains path:
[cmake]
[cmake] "/media/rbs42/data/Gebos/RBS42/tools/libcobjava/${_IMPORT_PREFIX}/include"
[cmake]
[cmake] which is prefixed in the source directory.
[cmake]
[cmake]
[cmake] Generating done
[cms-driver] Error during CMake configure: [cmake-server] Failed to compute build system.
This is why I removed $ENV{JAVA_HOME}/include $ENV{JAVA_HOME}/include/linux> from $<INSTALL_INTERFACE again.
The actual error I am getting in library B now is during compiling:
[build] /media/rbs42/data/rbs42/usr/include/libcobjava.h:1:10: fatal error: jni.h: No such file or directory
[build] #include <jni.h>
because library B does not have the include directories from library A that are not included in the $<INSTALL_INTERFACE. This is what one would expect. And thats the reason I added the following code before in library A.
set_property(TARGET JNI PROPERTY INTERFACE_INCLUDE_DIRECTORIES $ENV{JAVA_HOME}/include $ENV{JAVA_HOME}/include/linux)
which I assumed is taking care of propagating the include dependencies from library A to the "consuming" library B, although they are not part of the $<INSTALL_INTERFACE.
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)
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.
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}")