Can CMake require static libraries (e.g., ZLIB)? - c++

It has been years since I worked in C++, and I've never used CMake before. I'm trying to compile a program called ngmlr, which uses CMake. It worked seamlessly on other systems I tried to build it on. This time around, CMake finds ZLIB (Found ZLIB: /usr/lib64/libz.so (found version "1.2.3")), as required by ngmlr, but the subsequent make fails with ld: cannot find -lz.
I think I know what's happening: CMake found the dynamic ZLIB library (libz.so), but the CMakeLists.txt file requires static (I found the following option in the file: option(STATIC "Build static binary" ON)). As far as I can tell, the static library (libz.a) is missing on this machine. It's not in the same /usr/lib64 directory as libz.so. locate is not available.
Questions:
Does that seem correct?
For education, assuming this is the problem, can you force CMake to look specifically for static ZLIB? e.g., since the developer required static, it would have been nice to immediately know the missing static library was the problem, rather than the embarrassingly long amount of time it took me to figure it out.
I've looked extensively for a clear answer to both, but didn't find anything conclusive (e.g., Force cmake to use static libraries).
UPDATE
I did confirm that the problem is that ld could not find the static library. Now I'm particularly interested to know if the developer can tell CMake to throw an error if the static libraries are not present, and save someone else.
cmake version 2.8.8

Yes
Generally speaking it is up to Find-module authors. Some modules have special "static" option, others do not. Particularly Zlib module has not. That's why cmake global variable is set in subdirectory src/CMakeLists.txt: SET(CMAKE_FIND_LIBRARY_SUFFIXES ".a"). But it is invoked after find_package( ZLIB REQUIRED ) command. Looks like a bug.
Now I'm particularly interested to know if the developer can tell CMake to throw an error if the static libraries are not present, and save someone else.
REQUIRED means that error will be thrown if package was not found. In your case it should be thrown if you move SET(CMAKE_FIND_LIBRARY_SUFFIXES before find_package
Perhaps you can build your project if disable STATIC option
cmake -G"Unix Makefiles" _PATH_ -DSTATIC=OFF

I'm no cmake expert, but in case this helps anyone. I had found setting CMAKE_FIND_LIBRARY_SUFFIXES successfully loaded the static lib, but I only wanted this for finding ZLIB, so I saved the previous value, set CMAKE_FIND_LIBRARY_SUFFIXES and reset it like so:
set(_CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES})
set(CMAKE_FIND_LIBRARY_SUFFIXES "static.lib")
find_package(ZLIB ${ZLIB_VERSION} REQUIRED MODULE)
set(CMAKE_FIND_LIBRARY_SUFFIXES ${_CMAKE_FIND_LIBRARY_SUFFIXES})
unset(_CMAKE_FIND_LIBRARY_SUFFIXES)

Your CMakeLists.txt probably has this somewhere:
find_library(ZLIB z)
You can replace it with:
find_library(ZLIB libz.a)

Related

Build uWebSockets on Windows 10 with CMake

I want to use uWebSockets(UWS) in my C++ project to transfer images over the network. The setup will be running on multiple operating systems, so the best way of creating the build files seemed like using CMake.
However, I am new to CMake and having a hard time building UWS. I don't understand how to start working with the official repository on Windows 10, so I found another repository that includes a CMakeFiles.txt file and some of the dependencies (openssl, zlib, libuv, but it doesn't include uSockets for some reason). The root CMakeFiles.txt includes:
[...]
find_package(OpenSSL REQUIRED)
find_package(ZLIB REQUIRED)
find_path(LIBUV_INCLUDE_DIR uv.h)
find_library(LIBUV_LIBRARY NAMES uv uv1)
[...]
It looks straightforward, but when I try to run mkdir build && cd build; cmake .., it cannot find OpenSSL. Here is the error message it spits out:
[...]
[cmake] Could not find a package configuration file provided by "OpenSSL" with any
[cmake] of the following names:
[cmake]
[cmake] OpenSSLConfig.cmake
[cmake] openssl-config.cmake
[...]
The above error message suggests that I need to set up a config file for each of these libraries. Yet, if I understand the find_package docs correctly, the command itself searches the library in various locations under the root folder. What kind of a folder structure does the find_package need in order to work?
More generally, am I wasting my time with this alternative repo? Is there a better way of using UWS with Windows 10? The official repo has a question about how to use it on Windows but I don't understand how that's an answer to the question. It only points to this page where it says any specific build systems will not officially be supported.
Any help would be appreciated.
Importing dependencies with add_subdirectory seems like a good way around this. When I ran cmake, I was receiving LNK2019 Error. I realized the following code snippet I found online was causing the problem, and the system works when I delete it.
if(MSVC)
set(CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG} /NODEFAULTLIB:libcmt.lib /NODEFAULTLIB:msvcrt.lib")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /SUBSYSTEM:WINDOWS")
endif()

CMake and/or make error while adding boost to project

I started a fresh c++ project trying to use boost program_options. Unfortunately I have trouble with cmake; depending on what I try I either get a gmake error not beeing able to build a file or another one about target patterns not containing %.
Actual errors are:
While using ${Boost_LIBRARIES} (case 1): gmake error: No rule to build /usr/local/lib/libbooost_program_options.so
While using Boost::program_options (case 2): gmake error: Target pattern does not conaint "%". Stop.
I sourced my solution attempts from this SO thread: How to link C++ program with Boost using CMake
About case 1: this provides a step by step guide for this problem. Unfortunately after step one "check if the file exists" there is no hint at what to do if it DOES exists, which it does in my case.
stat /usr/local/lib/libboost_program_options.so
Datei: /usr/local/lib/libboost_program_options.so -> libboost_program_options.so.1.62.0
Other threads, such as "No rule to make target" error in cmake when linking to shared library suggest using finder scripts, which I already do.
edit: Thanks to a comment it turned out i was blind for parts of the error message: The path plugged into the makefile is "Boost::program_options-NOTFOUND" which will obviously result in an error.
About case 2: Target pattern contains no '%'. Makefile implies that it is a path problem with any of my paths. I have zero idea how to further debug the problem, as debugging cmake scripts seems to be not well supported. Info on this is hard to find on any search engine.
The two versions of cmake scripts I used look like this:
cmake_minimum_required(VERSION 3.13)
project(probsim)
set(CMAKE_CXX_STANDARD 17)
FIND_PACKAGE(Boost COMPONENTS program_options REQUIRED )
add_executable(probsim main.cpp)
target_link_libraries(probsim ${Boost_LIBRARIES})
# alternative: target_link_libraries(probsim Boost::program_options)
Results are:
-- Boost version: 1.62.0
-- Found the following Boost libraries:
-- program_options
-- Configuring done
-- Generating done
-- Build files have been written to: /home/ketzu/CLionProjects/probsim/cmake-build-debug
Summary: Cmake creates an invalid makefile one way or another, the reason seems to be related to paths used on my filesystem.
While I could find clues for the reasons of the problem, I could not solve them. It was most likely a problem with my system config on fedora.
But as an alternative solution to operating system development library management and troubles with ld I used conan.io with cmake to setup my development environment.
While this might not help everyone sumbling accross similar problems to mine, it might help some out.
Thanks everyone for the help.

How to know variable such as 'OpenCV' in CMake

I am using OpenCV with gcc and cmake. And I found a tutorial https://docs.opencv.org/3.4.0/db/df5/tutorial_linux_gcc_cmake.html .In the file CMakeLists.txt, there are some variables such as OpenCV and OpenCV_INCLUDE_DIRS.
cmake_minimum_required(VERSION 3.9)
project(VideoRecord)
set(CMAKE_CXX_STANDARD 11)
find_package(OpenCV REQUIRED)
include_directories(${OpenCV_INCLUDE_DIRS})
add_executable(VideoRecord main.cpp)
target_link_libraries(VideoRecord ${OpenCV_LIBS})
I want to know where to find these variables definition.
EDIT
Thanks #qbranchmaster's answer. I tried to search FindOpenCV.cmake but failed.
First try.
➜ ~ cmake --help-module-list | grep "FindOpen"
FindOpenACC
FindOpenAL
FindOpenCL
FindOpenGL
FindOpenMP
FindOpenSSL
FindOpenSceneGraph
FindOpenThreads
Another try.
➜ / find . "FindOpenCV.cmake"
In addition, my os is osx and I install cmake with brew. I comiple and install OpenCV manually.
These variables are part of the package config script shipping with OpenCV.
Note that find_package is a two-headed beast. The classic mode of operation is finding libraries through find-scripts. This is still the approach being used today for third-party libraries that are not aware of CMake. However, if your dependency is itself being built with CMake, it can provide a package config file instead, which allows for a more powerful mode of operation.
The idea here is that instead of you telling CMake how to find a dependency, the dependency itself tells CMake how clients can find it. This is the approach that is taken by libraries like OpenCV and Qt.
To answer your question, those variables are being set by the package config file in your local OpenCV installation, the template of which can be found in the OpenCV source code under cmake/templates/OpenCVConfig.cmake.in.
They are defined in CMake OpenCV module. CMake has numerous modules that aid in finding various libraries like OpenCV (FindOpenCV.cmake module).
Using this command you can get a list of modules that your CMake supports:
cmake --help-module-list
Some libraries come with their own *.cmake modules which should be installed in some system path. If you are using Ubuntu, your cmake modules should be localised in:
/usr/share/cmake/Modules/
If not, just search system for file FindOpenCV.cmake. In that file you will find these variables.
In general, you get variable names from the documentation or source code of the package you want to find.
Often you can derive the name to put into find_package from the provided FindFoo.cmake module file name, because "Foo" would be the name. The find module is either part of CMake or comes with the third-party library.
If there is no find module, some modules provide FooConfig.cmake files, where "Foo" is again the string to put into find_package.
If you have neither a find nor a config file, you need to find the library by other means, e.g., FindPkgConfig or find_library / find_file.

Using google protobuf with libraries in cmake on Windows, Visual Studio 2013

I have a CMake project with several sub-directories and library modules that eventually get built into client and server libraries, and those libraries are used from executable to test them. I am trying to use Google's protobuf library inside one of those libraries. I am creating my sub-library as follows:
include_directories(
.
../rendering_backend
../shared
${MY_THIRDPARTY_DIR}/protobuf/include
)
add_library(Client STATIC
client.cpp
client.hpp
../common.hpp
../shared/protobufs/my_bufs.pb.cc
../shared/protobufs/my_bufs.pb.h
)
target_link_libraries(Client
RenderingBackend
${MY_THIRDPARTY_DIR}/protobuf/lib/libprotobufd.lib
)
The executable is declared as follows:
add_executable(TEST_Client
client_tester.cpp
../src/rendering_backend/rendering_backend.hpp)
target_link_libraries(TEST_Client Client)
All these files seem to be generating properly, but when I build, I get the following error (and many just like it):
libprotobufd.lib(zero_copy_stream_impl.obj) : error LNK2038: mismatch detected for 'RuntimeLibrary': value 'MTd_StaticDebug' doesn't match value 'MDd_DynamicDebug' in client_tester.obj
I have gone back to the protobuf solution and verified that all projects are set to use /MDd in their Runtime Library setting. It was generated following the guide at https://github.com/google/protobuf/tree/master/cmake.
I have seen many questions and answers about protobufs, but none seem to address this problem. I don't know what could be trying to build /MTd when everything is set to /MDd inside Visual Studio.
Assuming that this process would work if I were doing it correctly, I can only assume I'm doing something wrong. What is the intended way to do something like this?
[EDIT]
I was trying to use protobuf 3.0.0 here.
In order for find_package to identify the correct paths, you must edit the CMAKE_PREFIX_PATH variable to search for libraries. This code allows it to find the path correctly, assuming that you have correctly set up THIRDPARTY_DIR and you downloaded the release version of protobuf (2.6.1 as of this writing):
set(CMAKE_PREFIX_PATH
${CMAKE_PREFIX_PATH}
${THIRDPARTY_DIR}/protobuf-2.6.1
)
Protobuf3 can also be used but in addition to setting the install path in CMAKE_PREFIX_PATH, you must also supply the CONFIG argument to find_package as follows:
find_package(Protobuf CONFIG REQUIRED)
...assuming Protobuf is required.
In my case, I configured Protobuf 3.0.0 beta 2 to install to a folder "install" within its own directory:
set(CMAKE_PREFIX_PATH
${CMAKE_PREFIX_PATH}
${THIRDPARTY_DIR}/protobuf-3.0.0-beta-2/install
)
find_package(Protobuf CONFIG REQUIRED)
(Thanks to tamas.kenez for correcting me on this.)
Note that I had to build the release library before find_package(Protobuf) would return without errors. I originally only build the debug libraries.
I also had to be cautious of which MSVC runtime I build with. Dynamic seems to be the default for most projects, but Protobuf3 builds with the static runtime unless you configure it to do otherwise (there's a checkbox if you're using the GUI). Linking static runtime libraries to dynamic runtime executables causes all kinds of linker problems and redefinitions, so be careful of that.
Lastly, CMake GUI seems to retain some information about directory structures until you reload the project (or possibly restart the program entirely); so I hit a snag in trying to change which version of protobuf I used when CMake kept finding a directory structure I had already deleted, even after clearing the whole build directory. (Solved by clearing the build directory and relaunching CMake GUI and reloading the base project.)
You can use git-subtree or git-submodule to make google protobuf sources part of your solution and build it with your project.
Add to your top-level CMakeLists.txt
add_subdirectory("third-party/protobuf/cmake")
include_directories("third-party/protobuf/src")
to get all protobuf targets.
Then you can add dependency to protobuf with
target_link_libraries(YourLibrary libprotobuf libprotobuf-lite libprotoc)
Hope this helps.

cmake find modules wrt version

I have a question regarding CMake: recently a lot of modules have been added to the standard installation, such as GLEW or Mercurial.
However a lot of installation base might have an older version without all the new modules available, so you are forced to ship your own version of (eg) FindGLEW.cmake
Is it possible to check whether a given FindXXX module is available and in that case use it, otherwise supply a proper alternative? Or even check cmake version at runtime (but that's not always reliable and a pain to maintain)...?
Thanks for any help.
The default search behaviour of CMake's include command w.r.t modules is:
the file with name <modulename>.cmake is searched first in CMAKE_MODULE_PATH, then in the CMake module directory.
(there's a bit more to it - see the docs or run cmake --help-command include)
What you're asking for appears to be the opposite to this; first check for an official module in the CMake module directory, and if none exists, fall back to use your own.
Assuming your modules are in ${CMAKE_SOURCE_DIR}/my_cmake_modules, you could reverse CMake's default behaviour by doing:
set(CMAKE_MODULE_PATH ${CMAKE_ROOT}/Modules ${CMAKE_SOURCE_DIR}/my_cmake_modules)
If you name your own modules exactly as per the official ones, then this should achieve your goal. If you wish to revert to the normal CMake behaviour later in your script, you can do:
set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/my_cmake_modules)
as a possible alternative to the solution above, I found this cmake policy
CMP0017
Prefer files from the CMake module directory when including from
there.
Starting with CMake 2.8.4, if a cmake-module shipped with CMake (i.e.
located in the CMake module directory) calls include() or
find_package(), the files located in the the CMake module directory
are preferred over the files in CMAKE_MODULE_PATH. This makes sure
that the modules belonging to CMake always get those files included
which they expect, and against which they were developed and tested.
In call other cases, the files found in CMAKE_MODULE_PATH still take
precedence over the ones in the CMake module directory. The OLD
behaviour is to always prefer files from CMAKE_MODULE_PATH over files
from the CMake modules directory.
This policy was introduced in CMake version 2.8.4. CMake version
2.8.9 warns when the policy is not set and uses OLD behavior. Use the
cmake_policy command to set it to OLD or NEW explicitly.
Hope this helps.