I am using Windos 10, Clang 11.0 installed from Visual Studio installer. I want to use library redis++, so I first installed library hiredis (I built it with selecting toolset "cmake -T ClangCL ...") and then installed redis++ with similar cmake command.
My CMakeLists.txt file for simple test project looks like this:
cmake_minimum_required(VERSION 3.18)
project(HELLO)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
add_executable(target hello.cpp)
find_package(hiredis)
target_include_directories(target PUBLIC ${HIREDIS_HEADER})
target_link_libraries(target ${HIREDIS_LIB})
find_package(redis++)
target_include_directories(target PUBLIC ${REDIS_PLUS_PLUS_HEADER})
target_link_libraries(target ${REDIS_PLUS_PLUS_LIB})
hello.cpp looks like:
#include <sw/redis++/redis++.h>
using namespace sw::redis;
in main(int argc, char *argv[]){
auto redis = Redis("tcp://127:0:0:1:6379");
const sw::redis::StringView key = "test";
redis.rpop(key);
return 0;
}
When I build the project, I get error lld-link error: undefined symbol sw::redis::Redis::rpop. If I just call redis.pop() (without passing argument), I get too few arguments to function call.
So I am not really sure what is going on, if I call rpop() in invalid way, it sees the function signature and tells me I need to pass an argument, but when I pass it, it says linking error.
Successful call to
find_package(redis++)
creates IMPORTED targets redis++::redis++ for the shared library and redis++::redis++_static for the static library. For use Redis++ you need to link one of these targets into the executable:
target_link_libraries(target redis++::redis++)
(Linkage with the IMPORTED target automatically sets include directories, so the call to target_include_directories is not needed.)
The approach with using variables REDIS_PLUS_PLUS_HEADER and REDIS_PLUS_PLUS_LIB works if you set these variables in corresponding find_path and find_library calls, as described in their docs: https://github.com/sewenew/redis-plus-plus#build-with-cmake.
As with any other project, find_package approach (described at the beginning of that post) is always a preferred way.
Related
Newbee here on QT creator and CMake and apologies for the basic question but struggling to link simple external library to my main project. Here are the project paths:
build-QMLTest-Desktop_Qt_6_3_1_MinGW_64_bit-Debug // application binary path
QMLLib
build-mylib-Desktop_Qt_6_3_1_MinGW_64_bit-Debug // lib binary path
mylib
CMakeLists.txt
mylib.cpp // lib source path
mylib.h
QMLTest
CMakeLists.txt
main.cpp // application source path
Here is my how I am trying to link the static library (snipped of QMLTest/CMakeLists.txt). I am using this thread as reference:
How do I explicitly specify an out-of-tree source in CMake?
add_subdirectory(../QMLLib/mylib ../QMLLib/build-mylib-Desktop_Qt_6_3_1_MinGW_64_bit-Debug)
target_link_libraries(mylib)
set(PROJECT_SOURCES
main.cpp
qml.qrc
)
main.cpp
#include "../QMLLib/mylib/mylib.h"
int main(int argc, char *argv[])
{
Mylib mylib;
Yet, it won't resolve, here is the output
C:/Qt/Tools/mingw1120_64/bin/../lib/gcc/x86_64-w64-mingw32/11.2.0/../../../../x86_64-w64-mingw32/bin/ld.exe: CMakeFiles/QMLTest.dir/main.cpp.obj: in function `qMain(int, char**)':
C:/myroot/UITest/QMLTest/main.cpp:13: undefined reference to `Mylib::Mylib()'
collect2.exe: error: ld returned 1 exit status
I could not get an answer, so 50 points for grabs, since I cannot resolve this issue.
Ideally if you can point me out to recent project using CMake and QT Creator 8.0 making a simple project and library and link them together, it would be great.
At first, try to separate the directories to add in the add_subdirectory command arguments to be sure that everything within the library subdirectories is compiled. Then use target_link_libraries command properly:
add_subdirectory(../QMLLib/mylib)
set(PROJECT_SOURCES
main.cpp
qml.qrc
)
include_directories(../QMLLib/mylib/include)
# Link subdir target AFTER definition of the project target
add_library(myproject ${PROJECT_SOURCES})
target_link_libraries(myproject mylib)
I suggest you refer to the actual CMakeLists.txt file I used when importing my library into the existing project (despite being ROS-based, CMake works the same way). Just extract the sequence of commands from there.
I ended up re-arranging the folders and the solution is here:
Cannot add library source to cmake project on QT
where I just include the sources from a separate library project
I would like to use the Antlr framework in a project. I'm using CMake to build the project.
I would like to use the SHARED library version of Antlr, not the STATIC one. Its CMake file contains targets for both.
Antlr's github site explicity tells me to use the following code:
find_package(antlr4-runtime REQUIRED)
# add runtime include directories on this project.
include_directories( ${ANTLR4_INCLUDE_DIR} )
# add runtime to project dependencies
add_dependencies( Parsertest antlr4_shared )
# add runtime to project link libraries
target_link_libraries( Parsertest PRIVATE
antlr4_shared)
(another target, antlr4_static, exists, but shouldn´t be used.)
I copied it exactly like this and am getting the following error:
CMake Error at /usr/lib64/cmake/antlr4-runtime/antlr4-targets.cmake:82 (message):
The imported target "antlr4_static" references the file
"/usr/lib/libantlr4-runtime.a"
but this file does not exist.
I dont have the static library installed in my system as I have no intention of using it. Still, how do I make CMake stop looking for the wrong target in the first place? I use it nowhere in my CMakeLists.txt file and am puzzled by this behavior.
I have a library that needs to carry some constant data injected from the content of non-source files (in this case, OpenGL shader code). To achieve this, I'm using add_custom_command() to generate include files that I can then #include into my code to initialize const static variables.
This works perfectly with regular libraries (static or shared), but now I'd like to make my library header-only. The ability of C++ to let static methods return static data without running the risk of having that data duplicated in each translation unit ("magic statics") makes this possible.
The problem however is that CMake seems to assume that an INTERFACE library (which is the CMake feature that I'm using to create header-only libraries) does not need building - which, in this case, is wrong.
(I realize that there is no actual obligation for my library to be header-only. In this particular case, the reason I want this is that I would like the library, which is doing OpenGL, to remain independent of any specific binding library [such as GLEW or GLee or the newcomer glbinding]. By keeping my library header-only, I can leave that choice to the user - all he needs to do is #include the header of the binding library before mine.)
Does anyone see a way to have CMake trigger the header-generating custom commands, at the latest when the consumer project is being built?
EDIT: I just realized that I could have the "best of both worlds" as it were by keeping my library static but still keeping all my code except for the constant data in the header files. That way, there would still be no need to choose a specific OpenGL binding library.
However, there are still advantages to having a library be header-only - simplicity of use for one - so I'm leaving my question open.
EDIT #2: Here is the relevant part of my CMakeLists.txt file (I only stripped the library dependencies - all header-only - from the end):
set(SHADER_FILES "src/vertex.glsl" "src/fragment.glsl")
add_library(libGPCGUIGLRenderer INTERFACE)
target_sources(libGPCGUIGLRenderer INTERFACE ${SHADER_FILES})
target_include_directories(libGPCGUIGLRenderer BEFORE
INTERFACE
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:include>
)
# Embed shader files
source_group("Shader files" FILES ${SHADER_FILES})
set(GENERATED "${CMAKE_CURRENT_BINARY_DIR}/generated")
target_include_directories(libGPCGUIGLRenderer INTERFACE ${GENERATED})
# Find the GPC Bin2C utility
find_package(GPCBin2C REQUIRED)
# Add a custom target and a dependency for each shader file
foreach(shader ${SHADER_FILES})
get_filename_component(name "${shader}" NAME)
set(shader_header "${GENERATED}/${name}.h")
add_custom_command(
OUTPUT ${shader_header}
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${shader}
COMMAND GPCBin2C --input=${CMAKE_CURRENT_SOURCE_DIR}/${shader} --output=${shader_header}
)
target_sources(libGPCGUIGLRenderer INTERFACE ${shader_header})
endforeach()
Creating a static library with headers as the only sources worked for me. It is, of course, only a work-around.
Creating a static library with only header files results in an empty library. Mine says !<arch> as the only content.
CMake will automatically get the dependencies correct across sub-directories.
Since all sources are headers, you need to tell CMake which linker language should be used.
Code:
set(OUTDIR "${CMAKE_CURRENT_BINARY_DIR}/generated_include")
add_custom_command(
OUTPUT "${OUTDIR}/outfile.h"
# Replace the next two lines with a proper generating script.
COMMAND mkdir -p ${OUTDIR}
COMMAND touch ${OUTDIR}/outfile.h
)
# Note, I am only adding header files to the library.
add_library(generated-headers STATIC
"${OUTDIR}/outfile.h"
)
set_target_properties(generated-headers
PROPERTIES LINKER_LANGUAGE CXX)
target_include_directories(generated-headers PUBLIC ${OUTDIR})
Use in other directories like this:
# In any other directory of the same CMake project:
add_executable(main main.cpp)
target_link_libraries(main generated-headers)
Tested on CMake 3.2, 3.8 and 3.9. Using Ninja and Make generators.
You can use target_sources in CMake 3.1 to tell consumers to compile interface files:
add_library(source_only INTERFACE)
target_sources(source_only INTERFACE foo.cpp)
http://www.cmake.org/cmake/help/v3.1/command/target_sources.html
I ran into comparable problems when trying to use glad: https://github.com/Dav1dde/glad
It uses a custom CMake command to build a binding, which means the files you need to include in the project which uses glad do not exist, so that CMake does not build glad (which would create those files)...
I did not get to try it yet, but example 3 of the following link seems to be a good solution and I believe it may work in your case:
https://samthursfield.wordpress.com/2015/11/21/cmake-dependencies-between-targets-and-files-and-custom-commands/
I am building a project with cmake. The project uses the external library plplot; I have configured cmake to the library and headers, and that is cached in variables ${PLPLOT_LIBRARY}, ${PLPLOT_LIB_PATH} and ${PLPLOT_INCLUDE_PATH}. In the plplot library a function has changed name: plwid -> plwidth and I want to detect that. I have written a small try_compile() test:
try_compile(HAVE_PLWID ${CMAKE_BINARY_DIR} cmake/tests/test_plwid.c)
However this test will always fail, because I have to pass header and library information to the try_compile process. Invoking gcc manually like this:
gcc -I${PLPLOT_INCLUDE_PATH} cmake/tests/test_plwid.c -L${PLPLOT_LIB_PATH} -l${PLPLOT_LIBRARY}
works. However I don understand how to pass the necessary flags to the try_compilecommand: I have tried:
try_compile(HAVE_PLWID ${CMAKE_BINARY_DIR} cmake/tests/test_plwid.c
INCLUDE_DIRECTORIES ${PLPLOT_INCLUDE_PATH}
LINK_DIRECTORIES ${PLPLOT_LIB_PATH}
LINK_LIBRARIES ${PLPLOT_LIBRARY})
Then I just get the cmake configure error:
Attempt at a recursive or nested TRY_COMPILE in directory
/path/to/build
I am quite confident the ${PLPLOT_XXX} variables are correct, at least the rest of the build works fine based on these variables.
Update: If I invoke cmakewith the --debug_trycompile command and go to the build/CMakeFiles/CMakeTmp directory and invoke cmakethere manually as:
cmake . -DINCLUDE_DIRECTORIES=/path/plplot/include -DLINK_DIRECTORIES=/path/to/plplot/lib -DLINK_LIBRARIES=plplotd
The test program will build and link correctly; so it seems the challenge is to pass these options correctly to the try_compile() cmake command invocation?
The LINK_DIRECTORIES and INCLUDE_DIRECTORIES cannot be passed as options to try_compile but have to passed as extra flags with the CMAKE_FLAGS option in the following way:
try_compile(HAVE_PLWID "${CMAKE_BINARY_DIR}/temp" "${CMAKE_SOURCE_DIR}/tests/test_plwid.c"
LINK_LIBRARIES ${PLPLOT_LIBRARY}
CMAKE_FLAGS
"-DINCLUDE_DIRECTORIES=${PLPLOT_INCLUDE_PATH}"
"-DLINK_DIRECTORIES=${PLPLOT_LIB_PATH}")
Using CMake I want to check if a particular function (cv::getGaborKernel) from OpenCV library is available (it is available only in quite recent version of the library). If it is, I will use it in my code, if it is not, I redefine it in my code, in btw #ifdefs.
Here is a snippet of my CMakeLists.txt:
FIND_PACKAGE(OpenCV REQUIRED)
include_directories(${OpenCV_INCLUDE_DIRS})
get_property(inc_dirs DIRECTORY PROPERTY INCLUDE_DIRECTORIES)
set(CMAKE_REQUIRED_INCLUDES ${OpenCV_INCLUDE_DIRS})
set(CMAKE_REQUIRED_LIBRARIES ${OpenCV_LIBS})
INCLUDE(CheckCXXSourceCompiles)
CHECK_CXX_SOURCE_COMPILES(
"
#include <opencv2/imgproc/imgproc.hpp>
int
main()
{
cv::Mat toto = cv::getGaborKernel(cv::Size(11,11), 1,0,3,1,0, CV_64F);
}
" HAVE_OPENCV_GABOR)
if(HAVE_OPENCV_GABOR)
message("Using OpenCV Gabor implementation")
else(HAVE_OPENCV_GABOR)
message("Using custom Gabor implementation")
endif(HAVE_OPENCV_GABOR)
When deploying on a computer with recent OpenCV version (which does have cv::getGaborKernel), the test fails, forcing the redefinition of the function and some compilation errors.
The problem reside in the fact that OpenCV not beeing installed in standard directory, it first fails to locate the library. So the sample program cannot be built. However, after I properly set up OpenCV dependencies, the test for HAVE_OPENCV_GABOR is not run again as the failure is registered in the cache.
How can I force CMake to rerun the test in that case?
Just wrap your CHECK_CXX_SOURCE_COMPILES() call with
if(NOT OpenCV_INCLUDE_DIRS OR NOT OpenCV_LIBS)
...
endif()
Another solution - add unset(HAVE_OPENCV_GABOR CACHE) before running CHECK_CXX_SOURCE_COMPILES().