I've already downloaded an built HDF5 under Windows using CMake, I also generated an installer to install it under Program Files.
Below the CMakeLists.txt I wrote to be able to use HDF5 in a program I already wrote under Linux :
cmake_minimum_required(VERSION 2.8)
project(Hdf5DataFeed)
add_definitions(-DWINDOWS)
find_package(HDF5)
FIND_LIBRARY(HDF5_HL_LIBRARY hdf5_hl)
FIND_LIBRARY(ZLIB zlib)
find_library(ZMQ_LIB zmq)
find_package(VTK REQUIRED)
include(${VTK_USE_FILE})
include_directories(${ZMQ_LIB_INCLUDE})
aux_source_directory(. SRC_LIST)
add_executable(${PROJECT_NAME} ${SRC_LIST})
target_link_libraries(${PROJECT_NAME} ${ZLIB} "C:/Program Files/HDF_Group/HDF5/1.10.1/lib/libszip.lib" ${VTK_LIBRARIES} ${ZMQ_LIB} ${HDF5_LIBRARIES} ${HDF5_HL_LIBRARY} Qt5::Core Qt5::Gui Qt5::Widgets)
target_include_directories(${PROJECT_NAME} PRIVATE ${HDF5_INCLUDE_DIRS})
As you can see above, to link HDF5 under Visual Studio, I needed Zlib, Szip (that I had to enter an absolute path to it, I don't like that), HDF5 library and the HDF5 High Level (Lite) library.
These libraries are located under C:\Program Files\HDF_Group\HDF5\1.10.1\lib :
libhdf5.lib <============
libhdf5.settings
libhdf5_cpp.lib
libhdf5_hl.lib <=====
libhdf5_hl_cpp.lib
libhdf5_tools.lib
libszip.lib <=== ????
libzlib.lib <====
I use CMake-Gui to inform CMake of the libraries path (except for Szip, I don't know why CMake doesn't know about it, and why I don't have the possibility to just feed CMake the library directory instead of indicating the path of few of them).
I want to use CMake-GUI to inform CMake of Szip library path, but this last doesn't create an entry of it, I only have these entries related to HDF5 :
I'm having troubles with HDF5 also under Ubuntu (see this question : hdf5.h no such file or directory under Ubuntu and CMake).
For now, it's only under CentOS 7 that I didn't encounter any issues with HDF5.
If someone can give me/us a final solution that works both on Windows and Ubuntu that would be great !
Does this solution work for you?
cmake_minimum_required(VERSION 2.8)
project(Hdf5DataFeed)
# necessary?
add_definitions(-DWINDOWS)
find_package(HDF5 REQUIRED COMPONENTS C CXX HL)
find_package(ZLIB REQUIRED)
find_package(VTK REQUIRED)
include(${VTK_USE_FILE})
find_library(ZMQ_LIB zmq)
include_directories(${ZMQ_LIB_INCLUDE} ${HDF5_INCLUDE_DIR}
${ZLIB_INCLUDE_DIRS})
aux_source_directory(. SRC_LIST)
add_executable(${PROJECT_NAME} ${SRC_LIST})
target_link_libraries(${PROJECT_NAME} ${HDF5_LIBRARIES}
${HDF5_HL_LIBRARIES} ${ZLIB_LIBRARIES} ${VTK_LIBRARIES}
Qt5::Core Qt5::Gui Qt5::Widgets ${ZMQ_LIB})
Recommendation 1: Surely, there is a way to find Qt5 via find_package, i.e.,
find_package(Qt5 COMPONENTS Core Widgets REQUIRED)
and then add the correct variables to include_directories and target_link_libraries. Not sure whether such a possibility exists for the zmq library, though.
Recommendation 2: I think the call the aux_source_directory should be avoided in most cases. Create an explicit list of your source files instead.
For libszip, adding a find_library is better than putting an absolute link to it. For ZLib, it is preferable to use find_library as find_package will require you to feed CMake with an include directory which is not required for HDF5. Finally, it is preferable to use find_package for ZMQ, otherwise, we need to add manually the entry "ZMQ_LIB_INCLUDE".
Related
Context: I want to make a GameClient, GameServer, and custom library (which both Client and Server use) cross platform for Linux, Windows & MacOS. Server and Client both depend on various libraries I prefer linking statically, and headers. I heard I could do this by wrapping my 3 currently VisualStudio developed projects into a CMake environment, so I started by making CMakeLists.txt's for Server and Shared lib, which are the simplest and have fewer library dependencies.
Question: How can I adapt these CMakeLists.txt's (currently building on and for Windows), so I can choose if I want to compile for Windows or Linux (preferably from Windows)?
Shared Lib CMakeLists.txt:
cmake_minimum_required(VERSION 3.10)
project(MORPH_Server VERSION 1.0)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED True)
set(SFML_STATIC_LIBRARIES TRUE) #Link to statically
set(SFML_DIR "C:/libraries/SFML/SFMLx64SourceAndCompile")
find_package(SFML 2.5.1 COMPONENTS system network REQUIRED)
add_library(MORPH_Shared_Functions)
target_sources(MORPH_Shared_Functions
PRIVATE Transform.cpp
PRIVATE World.cpp
PRIVATE Player.cpp
PRIVATE PropsData.cpp
PRIVATE Prop.cpp
PRIVATE udp_network_manager.cpp
PRIVATE utility_functions.cpp
)
target_link_libraries(MORPH_Shared_Functions
sfml-system #Basically already found sfml modules and their dependencies (find-package)
sfml-network
)
target_include_directories(MORPH_Shared_Functions
PRIVATE C:/libraries/SFML/SFML-2.5.1/include
PRIVATE C:/libraries/GLM/glm
PRIVATE C:/libraries/CEREAL
)
Server CMakeLists.txt:
cmake_minimum_required(VERSION 3.10)
project(MORPH_Server VERSION 1.0)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED True)
configure_file(CmakeConfig.h.in CmakeConfig.h)
set(SFML_STATIC_LIBRARIES TRUE) #Link to statically
set(SFML_DIR "C:/libraries/SFML/SFMLx64SourceAndCompile")
find_package(SFML 2.5.1 COMPONENTS system network REQUIRED)
add_executable(MORPH_Server)
target_sources(MORPH_Server
PRIVATE Main.cpp
PRIVATE Game.cpp
PRIVATE CommandManager.cpp
PRIVATE ServerPlayer.cpp
PRIVATE ServerProp.cpp
PRIVATE ServerWorldState.cpp
PRIVATE UDP_Server_CS.cpp
)
add_library(MORPH_Shared_Functions STATIC IMPORTED)
set_target_properties(MORPH_Shared_Functions PROPERTIES IMPORTED_LOCATION C:/Users/dylan/Desktop/MORPH/MORPH_Shared_Functions/Build/Debug/MORPH_Shared_Functions.lib)
target_link_libraries(MORPH_Server
MORPH_Shared_Functions
sfml-system
sfml-network
)
target_include_directories(MORPH_Server
PRIVATE C:/Users/dylan/Desktop/MORPH/MORPH_Shared_Functions
PRIVATE C:/libraries/SFML/SFML-2.5.1/include
PRIVATE C:/libraries/GLM/glm
PRIVATE C:/libraries/CEREAL
)
You are lucky as both the three libraries you use export their packages correctly.
On linux, I will assume that the libraries are installed in ~/workspace/libraries.
The trick will be to use find_package for all your dependencies, and you must drop every custom Findxyz.cmake files.
Then, you will have to drop the ALL_CAPS for the directory name. This is important for CMake to find the packages correctly. On windows it may not matter as the filesystem is not case sensitive, but on linux it is.
So first, to make your CMakeLists completely agnostic on where to find the packages, we will create a new file called linux-dependencies.cmake with this content:
list(APPEND CMAKE_PREFIX_PATH "$ENV{HOME}/workspace/libraries")
list(APPEND CMAKE_PREFIX_PATH "path/to/morph/build") # can be relative
And windows-dependencies.cmake:
list(APPEND CMAKE_PREFIX_PATH "C:/libraries/")
list(APPEND CMAKE_PREFIX_PATH "$ENV{HOMEPATH}/Desktop/MORPH/build")
Of course, if you set the library installation directory relative to the project or on both platform relative to the home directory, you can have only one dependencies.cmake file.
Then, on your next cmake invocation, simply tell cmake to include that file:
cmake .. -DCMAKE_PROJECT_INCLUDE=linux-dependencies.cmake
Note that CMAKE_PROJECT_INCLUDE is only available since CMake 3.15. If you don't want to upgrade CMake or simply to provide a default, you can always include the file manually.
You CMakeLists file should look like this:
cmake_minimum_required(VERSION 3.15)
project(MORPH_Server VERSION 1.0)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED True)
configure_file(CmakeConfig.h.in CmakeConfig.h)
find_package(SFML 2.5.1 COMPONENTS system network REQUIRED)
find_package(glm 0.9.9 REQUIRED)
find_package(cereal REQUIRED) # cereal don't export version info as far as I know
# You will have to export your target or write a MORPH-config.cmake file
find_package(MORPH REQUIRED)
add_executable(MORPH_Server)
target_sources(MORPH_Server
PRIVATE Main.cpp
PRIVATE Game.cpp
PRIVATE CommandManager.cpp
PRIVATE ServerPlayer.cpp
PRIVATE ServerProp.cpp
PRIVATE ServerWorldState.cpp
PRIVATE UDP_Server_CS.cpp
)
# this take care of both linking and include dirs
target_link_libraries(MORPH_Server
MORPH_Shared_Functions
sfml-system
sfml-network
glm
cereal
)
Another thing that can help: set the same CMAKE_PREFIX_PATH as CMAKE_INSTALL_PREFIX or CMAKE_INSTALL_PREFIX/libname when installing libraries.
If you want to compile the linux executable on windows, I would advise to simply use WSL or to run the compiler inside Docker. VSCode actually has a nice extension to use a docker as a build environment, and as far as I know, can also use WSL as a build and run environment.
my 2 cents,
1
According to the find_package() search procedure documentation:
In all cases the <name> is treated as case-insensitive and corresponds to any of the names specified (<PackageName> or names given by NAMES).
ref: https://cmake.org/cmake/help/latest/command/find_package.html#search-procedure
note: personally I prefer to use PackageNameConfig.cmake than package-name-config.cmake ...
2
Why not simply add the CMAKE_PREFIX_PATH on the configure command line than passing by your dependencies.cmake files ?
3
For static linking, I would use a FetchContent() approach to control the "static-ness" since most of Linux distro will tend to build libraries as shared then put them in directories following the FHS.
3.1
You can also use flag to allow user to use system-wide libraries if they want (thus distro maintainers are happy as well as you can create a standalone artifact easily).
warning: Most libraries are not intended to be used inside a super build so you may need to patch them (i.e. PATCH_COMMAND git apply ...)
# enable CMP0077 so superbuild can set it.
option(BUILD_THIRDPARTY "Build the third party" ON)
...
# to allow recursive superbuild (add_subdirectory(morph_server) etc...)
# first check if third party target is not already present
# see: https://gitlab.kitware.com/cmake/cmake/-/issues/17735
if(NOT TARGET ThirdParty::ThirdParty)
if(BUILD_THIRDPARTY)
FetchContent_Declare(...)
set(BUILD_SHARED_LIBS OFF)
set(BUILD_EXAMPLES OFF) ...
FetchContent_MakeAvailable(third_party)
set(BUILD_SHARED_LIBS ${BUILD_SHARED_BCKP})
else()
find_package(ThirdParty REQUIRED)
endif()
endif()
4
You may also provide a default FindThirdParty.cmake.
if(UNIX)
list(APPEND CMAKE_PREFIX_PATH "$ENV{HOME}/workspace/libraries")
list(APPEND CMAKE_PREFIX_PATH "path/to/morph/build") # can be relative
else()
list(APPEND CMAKE_PREFIX_PATH "C:/libraries/")
list(APPEND CMAKE_PREFIX_PATH "$ENV{HOMEPATH}/Desktop/MORPH/build")
endif()
find_package(ThirdParty CONFIG REQUIRED)
So you don't have to play with CMAKE_PREFIX_PATH or dependencies.cmake etc. and users can still provide their own FindThirdParty.cmake and prepend the CMAKE_PREFIX_PATH if they want to change...
I am trying to use CGAL and PCL in the same project. Both PCL and CGAL should be installed correctly on my computer, since the examples work.
I created a CMakeList.txt file which references both PCL and CGAL I am able to configure it without the CMake GUI showing any problems, but when I open the project .sln the CGAL includes have errors
for example: Cannot open include file: 'CGAL/Simple_cartesian.h': No such file or directory
All the PCL includes work fine.
If I delete all the PCL references from the CMakeList.txt then the CGAL includes work. I am suspecting that I am doing something wrong in my CMakeList.txt.
Does anyone know what I am doing wrong?
Thank you!
Below is my CMakeList.txt
cmake_minimum_required(VERSION 3.1...3.15)
project(PC_Svr2)
find_package(CGAL QUIET)
if ( CGAL_FOUND )
# create a target per cppfile
file(GLOB cppfiles RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp)
foreach(cppfile ${cppfiles})
create_single_source_cgal_program( "${cppfile}" )
endforeach()
else()
message(STATUS "This program requires the CGAL library, and will not be compiled.")
endif()
find_package(PCL 1.2 REQUIRED)
include_directories(${PCL_INCLUDE_DIRS})
link_directories(${PCL_LIBRARY_DIRS})
add_definitions(${PCL_DEFINITIONS})
add_executable (PC_Svr2 cloud_viewer.cpp)
target_link_libraries (PC_Svr2 ${PCL_LIBRARIES})
message("PCL_IO_LIBRARIES - ${PCL_IO_LIBRARIES}")
file(GLOB cppfiles RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp)
foreach(cppfile ${cppfiles})
create_single_source_cgal_program( "${cppfile}" )
endforeach()
That is creating a single target from each of the cpp files in CMAKE_CURRENT_SOURCE_DIR. I don't think that is what you want.
If I understand things correctly, your code is in cloud_viewer.cpp, then you should remove the loop and just link with cgal with your target_link_libraries:
target_link_libraries(PCS_Svr2 CGAL::CGAL ${PCL_LIBRARIES})
You can have a look at that page for details.
I am trying to compile openGL file including "png.h" header file,
I got the following error:
Open GL version 2.1 ATI-3.2.24
libpng warning: Application built with libpng-1.4.12 but running with 1.6.37
error: png_create_read_struct returned 0.
Failed to read image texture from ../images/ceramic.png
My Cmakelists.txt file :
cmake_minimum_required (VERSION 3.13)
project (teapot)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
find_package(OpenGL REQUIRED)
find_package(GLUT REQUIRED)
find_package(PNG REQUIRED)
include_directories(${PNG_INCLUDE_DIR})
add_executable(teapot teapot.cpp)
target_link_libraries(teapot ${OPENGL_gl_LIBRARY} ${GLUT_LIBRARIES} ${PNG_LIBRARIES} )
set(CMAKE_CXX_FLAGS "-I ${CMAKE_OSX_SYSROOT} ${CMAKE_CXX_FLAGS} -std=c++11")
if (APPLE)
set (CMAKE_CXX_FLAGS "-Wno-deprecated-declarations ${CMAKE_CXX_FLAGS}")
endif ()
set_target_properties(teapot PROPERTIES
CXX_STANDARD 11
CXX_STANDARD_REQUIRED YES
CXX_EXTENSIONS NO
)
cmake . works fine, but when I execute ./teapot the above error occurred. Thanks for any help!
You've probably only have development libraries installed for libpng-1.4.12 and not for libpng-1.6.37 or some other "non-standard" installation.
But the message seems pretty clear you linked against an older version but have a newer version in the runtime path of loadable libraries.
find_package(PNG REQUIRED) is only going to search the "standard" locations via find_library().
You may also want to update your CMakeLists.txt file to use target_link_libraries( ... PNG::PNG). This is simpler than trying to use the PNG variables that get set; which is missing PNG_DEFINITIONS when compiling your project. Refer to the CMake manual buildsystem section about library targets.
You can inspect the variables by using the message() command to print out their values. Some of them will also be stored in CMakeCache.txt.
If libpng isn't in the standard locations then you have to use target_link_libraries( ... /path/to/lib) and target_include_directories( ... /path/to/lib/headers), etcetera to handle it.
I am currently using CMake to create a static library which utilizes a few of the static libraries from OpenCV 4 ( core imgcodecs video highgui imgproc ). My intention is to be able to bundle all of the required OpenCV static libraries into my own library so that I can distribute it as one library. Additionally, I want for the user of my library to not have to install OpenCV 4 on their system (but do not mind if the user has to do simple installs using apt-get install). I know there are tools for bundling static libraries (such as using ar for linux).
However, where I really am having the issue is with all the dependencies of OpenCV (such as libjpeg, libpng, etc). I don't necessarily mind if these libraries are bundled with mine or linked dynamically as they are relatively easy to install (can be installed with sudo apt-get install, whereas opencv4 needs to be built from source).
What is the best way to go about doing this?
This is my current CMakeLists.txt
It is currently working, but that is because I am using find_package(OpenCV REQUIRED) (which defeats the purpose of what I am trying to do). When I remove that line, the linker complains about not being able to find the OpenCV dependencies.
cmake_minimum_required(VERSION 2.8)
project(myproject)
set(CMAKE_CXX_STANDARD 14)
include_directories(${CMAKE_CURRENT_LIST_DIR}/include)
link_directories(${CMAKE_CURRENT_LIST_DIR}/lib)
find_package(OpenMP REQUIRED)
find_package(OpenCV REQUIRED)
set(JSON_BuildTests OFF CACHE INTERNAL "")
add_subdirectory(nlohmann_json)
list(APPEND LINKER_LIBS opencv_core opencv_highgui opencv_video opencv_imgcodecs libmxnet.so libncnn.a nlohmann_json::nlohmann_json)
file(GLOB SRC${CMAKE_CURRENT_LIST_DIR}/src/*.cpp${CMAKE_CURRENT_LIST_DIR}/main.cpp)
add_library(myproject ${SRC})
target_link_libraries(myproject ${LINKER_LIBS} ${OpenMP_CXX_FLAGS})
To elaborate on my question. I build my project which generates libmyproject.a. I then take this library and will eventually extract the symbols from the OpenCV libs (libopencv_core.a libopencv_highgui.a libopencv_imgcodecs.a libopencv_video.a) and add them to my lib (for the time being, I have not yet done this step, which is why in the below example I am linking libopencv_*). I then use my library in a new project, for which the CMakeLists.txt is shown below:
cmake_minimum_required(VERSION 2.8)
project(myproject-driver)
set(CMAKE_CXX_STANDARD 14)
include_directories(${CMAKE_CURRENT_LIST_DIR}/include)
link_directories(${CMAKE_CURRENT_LIST_DIR}/lib)
find_package(OpenMP REQUIRED)
add_executable(myproject-driver main.cpp)
target_link_libraries(myproject-driver myproject libncnn.a ${OpenMP_CXX_FLAGS} libmxnet.so libopencv_core.a libopencv_highgui.a libopencv_imgcodecs.a libopencv_video.a)
Building this generates the following errors:
Linking CXX executable myproject-driver
/usr/bin/ld: /home/nchafni/Cyrus/myproject/lib/libopencv_imgcodecs.a(grfmt_jpeg.cpp.o): undefined reference to symbol 'jpeg_default_qtables##LIBJPEG_8.0'
//usr/lib/x86_64-linux-gnu/libjpeg.so.8: error adding symbols: DSO missing from command line
collect2: error: ld returned 1 exit status
How can I fix this. Is there some CMake command which will link all these dependencies for me? Do I need to manually track down each dependency of those libopencv_* libs and link those manually? Once again, this is assuming that the person using libmyproject.a can't use find_package(OpenCV REQUIRED) as it won't be defined as they have not installed OpenCV on their machine.
First of all, don't use the super old and outdated version 2.8 of CMake. CMake 3.x is so much more powerful and pretty straightforward to use.
Some tips for modern CMake.
Don't use file(GLOB), see here why that is.
Don't use directory wide instructions, rather use target instructions, e.g. target_include_directories vs. include_directories.
Don't use string variables like ${<PACKAGE_NAME>_LIBRARIES}, rather use targets, e.g. <Package_NAME>::lib
When using targets instead of string variables, all the properties (including LINK_INTERFACE) of that target will be populated to the library/executable when calling target_link_libraries, so no more include_directories,link_directories, etc.
myproject
cmake_minimum_required(VERSION 3.14)
project(myproject)
set(CMAKE_CXX_STANDARD 14)
find_package(OpenMP REQUIRED)
find_package(OpenCV REQUIRED)
set(JSON_BuildTests OFF CACHE INTERNAL "")
add_subdirectory(nlohmann_json)
set(SOURCES ...) # list all the source files here
add_library(myproject ${SOURCES})
target_include_directories(myproject PUBLIC # give it a scope
${CMAKE_CURRENT_LIST_DIR}/include
)
target_link_libraries(myproject PUBLIC # give it a scope
opencv_core # using the target, you will get all LINK_LIBRARIES
opencv_highgui
opencv_video
opencv_imgcodecs
libmxnet.so # where is this coming from?
libncnn.a # where is this coming from?
nlohmann_json::nlohmann_json
OpenMP::OpenMP_CXX ## linking against a target, CXX_FLAGS will be populated automatically
)
myprojec-driver
cmake_minimum_required(VERSION 3.14)
project(myproject-driver)
set(CMAKE_CXX_STANDARD 14)
add_executable(myproject-driver main.cpp)
target_link_libraries(myproject-driver PUBLIC # give it a scope
myproject # gets all dependencies through the LINK_INTERFACE
)
I'm building a project in Cpp that will communicate with my Java apps via rabbitmq and post updates to twitter. I'm using a few libraries from github
rabbitmq-c
Rabbit installed to /usr/local/lib64
jansson - json library
I installed this a while back for another project, went to /usr/local/lib
twitcurl - C lib for Twitter API
Got installed to /usr/local/lib
If it matters, I'm using CLion as my IDE, which displays jansson and rabbit under auto-complete when defining includes - so that's picking the libs off my system somehow
e.g.
#include <jansson.h>
#include <amqp.h>
I link them using the target_link_libraries(name libs...) and I see output saying
build$ cmake ..
CMake Error at CMakeLists.txt:30 (target_link_libraries):
Cannot specify link libraries for target "twitcurl" which is not built by
this project.
I set LD_LIBRARY_PATH
export LD_LIBRARY_PATH=/usr/local/lib:/usr/local/lib64
I try to set the CMAKE_LIBRARY_PATH to include usr/local/lib and lib64 but doesn't seem to have any effect. Here's my CMakeLists.txt file
#
# This is a CMake makefile. You can find the cmake utility and
# information about it at http://www.cmake.org
#
cmake_minimum_required(VERSION 2.6)
set(PROJECT_NAME twitterUpdater)
set(SOURCE_FILES main.cpp)
set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE)
set(CMAKE_LIBRARY_PATH ${CMAKE_LIBRARY_PATH} "/usr/local/lib"
"/usr/local/lib64")
project(${PROJECT_NAME})
find_package(X11 REQUIRED)
find_package(OpenCV REQUIRED)
IF (X11_FOUND)
INCLUDE_DIRECTORIES(${X11_INCLUDE_DIR})
LINK_LIBRARIES(${X11_LIBRARIES})
ENDIF ( X11_FOUND )
IF (OpenCV_FOUND)
include_directories(${OpenCV_INCLUDE_DIRS})
link_libraries(${OpenCV_LIBS})
ENDIF(OpenCV_FOUND)
add_executable(${PROJECT_NAME} ${SOURCE_FILES})
target_link_libraries(${project_name} twitcurl jansson rabbitmq)
What's confusing me is another project I have uses jansson by simply adding it here TARGET_LINK_LIBRARIES(${project_name} dlib jansson)
What did I miss?? Thanks
CMake variables are case sensitive, thus the variable ${project_name} results in an empty string. Use ${PROJECT_NAME} instead, i.e.:
target_link_libraries(${PROJECT_NAME} twitcurl jansson rabbitmq)
Running CMake with the flag --warn-uninitialized helps you detect mistakes like this.