How to tell CMake to find the lib in local folder through command line? - cmake

I am trying to link my local version of gflags (which is in ~/mylibs/gflags) while compiling google-test. In gtest's CMakeLists.txt, it's using find_package:
if (WITH_GFLAGS)
find_package (gflags 2.2.0)
if (gflags_FOUND)
set (HAVE_LIB_GFLAGS 1)
determine_gflags_namespace (gflags_NAMESPACE)
endif (gflags_FOUND)
endif (WITH_GFLAGS)
I don't want to modify the CMakeLists.txt file. Is there anyway to tell cmake to find the package in my folder ?
Thanks!

The gflags documentation describes specifying the location of a non-standard installation when using CMake:
The gflags_DIR variable must be set to the <prefix>/lib/cmake/gflags directory containing the gflags-config.cmake file
In your case, this might look like:
cmake -Dgflags_DIR=/home/blackball/mylibs/gflags/lib/cmake/gflags [...]

Since you are integrating gflags as subproject in a super cmake, you basically want find_package() to be a no-op if you have it in your "meta-project" source dir. This can be done by overloading the find_package() command.
Top CMakeLists.txt:
# Use find_package everywhere, no-op if it's a subproject
macro(find_package)
if(NOT TARGET ${ARGV0} AND NOT TARGET ${ARGV0}::${ARGV0})
_find_package(${ARGV})
else()
if(TARGET ${ARGV0})
get_target_property(TGT_VER ${ARGV0} VERSION)
set(TGT ${ARGV0})
else()
get_target_property(TGT_VER ${ARGV0}::${ARGV0} VERSION)
set(TGT ${ARGV0}::${ARGV0})
endif()
message(STATUS "Found ${ARGV0}: CMake Target ${TGT} (found version \"${TGT_VER}\")")
set(${ARGV0}_FOUND TRUE)
endif()
endmacro()
note: for gflags you may need to "force" gflags_NAMESPACE also since gflags it's a source not a binary (cf glog issue ToDo)

Related

About Specifying EIGEN3_DIR variable not use

My computer has multiple versions of the eigen library. I have an eigen3 in the /usr/include/ and another eigen3 in the /usr/local/. I use the set() command in cmakelists, but the compiler only uses the eigen library in the/usr/include directory. Here are my cmakelists.txt settings
`
cmake_minimum_required(VERSION 2.8.3)
project(cmake_test)
set(EIGEN3_DIR "/usr/local/eigen-3.3.9/share/eigen3/cmake/")
find_package(Eigen3)
include_directories(
# "/usr/local/eigen-3.3.9/include/eigen3/"
${PROJECT_SOURCE_DIR}/include
${EIGEN3_INCLUDE_DIR}
)
message("EIGEN3_INCLUDE_DIR =======" ${EIGEN3_DIR})
message("EIGEN3_INCLUDE_DIR =======" ${EIGEN3_INCLUDE_DIR})
add_executable(cmake_test src/main.cpp)
`
Does anyone know where I went wrong
I hope someone can tell me how cmake searches for header files, library files, and Search order of the find_ package() command

How do I use find_package in CMakeLists.txt such that if an optional dependency is not installed, I still get a makefile?

My goal is to create a CMakeLists.txt file that builds a suite of programs for the local system. If the conditions for building some programs are not satisfied, I wish to be able to build the rest of the programs. The sticking point seems to be gtk, but bear in mind that I don't think a gtk-specific method is the best choice.
For many modules you'd want to build with, you can use
find_package(PkgConfig REQUIRED)
To set up the pkg-config wrapper pkg_check_Modules and if you don't use REQUIRED you can check the _FOUND variable:
pkg_check_Modules(FT REQUIRED freetype2)
if (FT_FOUND)
message(STATIC "Found freetype2")
#Continue and succeed, using FreeType library
else()
message(STATIC "Didn't find freetype2")
#Continue and succeed, without using FreeType library
endif()
Other libraries don't seem to work with pkg_check_modules so I have resorted to find_package
find_package(GTK2 2.0 QUIET gtk)
if (GTK2_FOUND)
...
endif()
Here's a complete reduction:
cmake_minimum_required(VERSION 3.6.2)
project (test C CXX)
set (SOURCE a.cpp b.cpp)
find_package(AMAZING 2.0 QUIET amazing_testing)
if (AMAZING_FOUND)
list(APPEND SOURCE c.cpp)
else()
list(APPEND SOURCE d.cpp)
endif()
add_executable(test ${SOURCE})
The above allows my whole CMakeLists.txt to proceed to the end, but I get an error, no makefile is created, and build/CMakeFiles/CMakeOutput.log doesn't even mention gtk:
CMake Error at gtk/CMakeLists.txt:4 (find_package):
find_package called with invalid argument "amazing_testing"
## here would be further cmake processing logs from other necessary setup
-- Configuring incomplete, errors occurred!
See also "/home/menright/bit/build/CMakeFiles/CMakeOutput.log".
How can I tweak such a usage of find_package so that if the optional package does not exist, the configure will complete successfully anyway? Alternatively, what should I use instead of find_package that will concisely set up usage of a library the way pkg_check_modules does and yet allow success if the library is not available?

How to find static version of zlib in CMake?

I'm on cmake version 3.12.1 and want to build a static executable that uses ZLIB. I have both the static (libz.a) and shared (libz.so) libraries on my machine. How can I tell find_package(ZLIB) to return the static version? Maybe there's another way to find libz.a as well?
My present workaround is to specify:
SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -static")
Then:
target_link_libraries (my_binary z lib1 lib2)
Critique on this approach is also welcome!
As of CMake 3.24, use: set(ZLIB_USE_STATIC_LIBS "ON")
Source
Your approach is valid given the limitations of the CMake module called by find_package(ZLIB), specifically FindZLIB.cmake. While other FindXXX.cmake modules have a special option for grabbing static libraries, the zlib module does not.
There are already a few questions on SO about this topic, but some are older than others, so there are a few options.
You can instead apply the -static flag on a more granular level (rather than editing the global CMAKE_EXE_LINKER_FLAGS variable) by adding it to your target_link_libraries call. This way it will apply only to that target -- useful if you are building other non-static targets.
You could also tell CMake to search for static libraries explicitly by setting CMAKE_FIND_LIBRARY_SUFFIXES. When find_package is called, CMake can search for libraries ending in .a using this:
SET(CMAKE_FIND_LIBRARY_SUFFIXES ".a")
find_package(ZLIB REQUIRED)
If you have control over installing zlib, for example, you are installing dependencies in a Continuous Integration setup, I would recommend to just remove the zlib dynamic library.
zlib doesn't have the option to build statically or dynamically, it automatically generates both versions. However FindZlib.cmake prioritizes the dynamic version.
I find the following approach to be better in case you don't have access to modify third parties repositories CMakeLists.txt that needs zlib:
if (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
set(_compiler_is_msvc ON)
endif()
option(ZLIB_FORCE_STATIC "Remove the dynamic libraries after zlib install" ON)
mark_as_advanced(ZLIB_FORCE_STATIC)
set(OUTPUT_BUILD_DIR ${CMAKE_CURRENT_BINARY_DIR} CACHE PATH "Base folder where builds and source folder will be installed: i.e. OUTPUT_BUILD_DIR/zlib")
if(_compiler_is_msvc)
set(ZLIB_GIT_TAG cacf7f1d4e3d44d871b605da3b647f07d718623f) # Version 1.2.11
message(STATUS "ZLIB_VERSION: ${ZLIB_GIT_TAG} : Version 1.2.11")
set(ZLIB_BUILD_DIR ${OUTPUT_BUILD_DIR}/zlib-build)
set(ZLIB_INSTALL_DIR ${OUTPUT_BUILD_DIR}/zlib)
set(ZLIB_SRC_FOLDER_NAME zlib-src)
set(ZLIB_SRC_DIR ${OUTPUT_BUILD_DIR}/${ZLIB_SRC_FOLDER_NAME})
set(ZLIB_GIT_REPOSITORY "https://github.com/madler/zlib")
ExternalProject_Add(ep_zlib
GIT_REPOSITORY ${ZLIB_GIT_REPOSITORY}
GIT_TAG ${ZLIB_GIT_TAG}
# GIT_SHALLOW TRUE
GIT_PROGRESS TRUE
CMAKE_GENERATOR ${CMAKE_GENERATOR}
SOURCE_DIR ${ZLIB_SRC_DIR}
BINARY_DIR ${ZLIB_BUILD_DIR}
CMAKE_ARGS
-DCMAKE_C_COMPILER:FILEPATH=${CMAKE_C_COMPILER}
-DCMAKE_CXX_COMPILER:FILEPATH=${CMAKE_CXX_COMPILER}
-DCMAKE_BUILD_TYPE:STRING=${SGEXT_CMAKE_BUILD_TYPE}
-DBUILD_SHARED_LIBS:BOOL=OFF
-DCMAKE_INSTALL_PREFIX=${ZLIB_INSTALL_DIR}
)
if(ZLIB_FORCE_STATIC)
ExternalProject_Add_Step(
ep_zlib zlib_remove_dll
COMMENT "Remove zlib.lib and zlib.dll, leaves only zlibstatic.lib"
DEPENDEES install
COMMAND ${CMAKE_COMMAND} -E remove -f ${ZLIB_INSTALL_DIR}/lib/zlib.lib ${ZLIB_INSTALL_DIR}/bin/zlib.dll
)
endif()
endif()
The last step removes the dynamic version, so the default FindZLIB will find the static library.
The best solution I found was to name the library explicitly when calling CMake:
cmake -DZLIB_LIBRARY=/usr/lib/x86_64-linux-gnu/libz.a /path/to/source
I would not recommend the solution proposed by #phcerdan because in my case the installed shared library was colliding with an already installed version, so the only solution was to make sure it never gets installed in the first place. The key idea is to disable completely the targets installation using SKIP_INSTALL_LIBRARIES, and instead to "install" the static library manually. Nonetheless, my solution is quite similar:
EXTERNALPROJECT_ADD(zlib_external
GIT_REPOSITORY https://github.com/madler/zlib.git
GIT_TAG v1.2.11
CMAKE_ARGS
-DSKIP_INSTALL_FILES=ON # Disable install of manual and pkgconfig files
-DSKIP_INSTALL_LIBRARIES=ON # Do not install libraries automatically. It will be handled manually to avoid installing shared libs
-DBUILD_SHARED_LIBS=OFF
-DCMAKE_TOOLCHAIN_FILE=${CMAKE_TOOLCHAIN_FILE}
-DCMAKE_INSTALL_PREFIX:PATH=${CMAKE_INSTALL_PREFIX}
-DCMAKE_C_FLAGS:STRING=${CMAKE_COMPILE_FLAGS_EXTERNAL}
${EXTERNALPROJECT_BUILD_TYPE_CMD}
INSTALL_DIR ${CMAKE_INSTALL_PREFIX}
)
if(NOT WIN32)
set(zlib_BUILD_LIB_PATH "<BINARY_DIR>/libz.a")
set(zlib_PATH "${CMAKE_INSTALL_PREFIX}/lib/libz.a")
else()
set(zlib_BUILD_LIB_PATH "<BINARY_DIR>/Release/zlibstatic.lib")
set(zlib_PATH "${CMAKE_INSTALL_PREFIX}/lib/zlibstatic.lib")
endif()
ExternalProject_Add_Step(
zlib_external zlib_install_static_only
COMMENT "Manually installing only static library"
DEPENDEES install
COMMAND ${CMAKE_COMMAND} -E copy ${zlib_BUILD_LIB_PATH} ${zlib_PATH}
)

Cmakelist working outside of Clion

I've wanted to use Clion for awhile but I've always had trouble with Cmake. Armed with Cygwin, I've almost gotten this stupid thing to work.
The issue is while I can compile a cmake file from within a cygwin terminal, in Clion I am told it cannot find the library I want.
Error:A required package was not found
The cmakelist.txt file
cmake_minimum_required(VERSION 3.3)
project(Test)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
set(PKG_CONFIG_PATH /usr/lib/pkgconfig)
set(PKG_CONFIG_EXECUTABLE /usr/bin/pkg-config.exe)
set(SOURCE_FILES main.cpp)
add_executable(Test ${SOURCE_FILES})
INCLUDE(FindPkgConfig)
pkg_check_modules(SDL2 REQUIRED "sdl2")
MESSAGE(STATUS "SDL library: " ${SDL2_LDFLAGS})
TARGET_LINK_LIBRARIES(Test ${SDL2_LDFLAGS})
I have no idea if setting the variables PKG_CONFIG_PATH and others work, but they successfully build a makefile for my use in cygwin that builds correctly.
I've deleted the cache, remade the project and everything. It just refuses to work in Clion
If I understood correctly, your cmake config is unable to find SDL library. I found it better to use find_package command instead of pkg_check_modules.
In order to find_package(SDL2) to work, there must be FindSDL2.cmake module in directory, specified by CMAKE_MODULE_PATH variable (usually, it is cmake/Modules directory inside your source tree).
FindSDL2.cmake is not a part of CMake, but you can find one online easily (check my own modules, for example: https://github.com/dragn/cmake-modules).
Refer to this doc for details: https://cmake.org/Wiki/CMake:How_To_Find_Libraries.
Put FindSDL2.cmake to cmake/Modules directory and add this to your CMakeLists.txt:
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_SOURCE_DIR}/cmake/Modules)
find_package(SDL2 REQUIRED)
include_directories(${SDL2_INCLUDE_DIR})
...
target_link_libraries(${PROJECT_NAME} ${SDL2_LIBRARY})
NOTE: Sadly, it appears that Leonardo has not succeeded in finding volunteers for maintaining FindSDL2.cmake in SDL community: https://cmake.org/Bug/view.php?id=14826.

Getting a CMake Error: Cannot specify link libraries for target which is not built by the project

I am implementing CMake in my code but I'm getting the error
"Cannot specify link libraries for target "Qt5::Widgets" which is not built by the project".
Below are the contents of the CMakeLists.txt:
#Specify the version being used aswell as the language
cmake_minimum_required(VERSION 2.6)
#Name your project here
project(eCAD)
#Sends the -std=c++11 flag to the gcc compiler
ADD_DEFINITIONS(-std=c++11)
#This tells CMake to main.cpp and name it eCAD
add_executable(eCAD main.cpp)
#include the subdirectory containing our libs
add_subdirectory (gui)
include_directories(gui)
#include Qt directories
find_package(Qt5Widgets)
find_package(Qt5Core)
find_package(Qt5Designer)
SET(QT_USE_QTDESIGNER ON)
#link_libraries
target_link_libraries(Qt5::Widgets Qt5::Core)
In addition to the accepted answer: An important detail is to place target_link_libraries after the add_executable and find_package lines, so all linked components are known.
The first argument of target_link_libraries is the target name:
target_link_libraries(eCAD Qt5::Widgets Qt5::Core)
Also, do not confuse target name with the project name:
a command project specifies a project name, but
a target is the one created with add_executable, add_library or add_custom_target.
The error message is about the target.
Set you_lib_name before setting target_link_libraries
set(you_lib_name libname)
target_link_libraries(you_lib_name Qt5::Widgets Qt5::Core)