CMake - finding external libraries - c++

I have a project with the following structure:
projectName-master/
data/
source/
thirdparty/ (here is placed FindSFML.cmake file)
.gitignore
CMakeLists.txt
README.md
SOURCES.md
TODO.md
I use CMake 2.8.11.1 (cmake-gui) to generate visual studio sln file. Paths are set this way:
where is the source code: E:/projectName-master
where to build the binaries: E:/projectName-master/source (1.Can I choose other directory or it should be set to the directory which contains source files: h, cpp etc. ?)
Next I choose: Configure -> "Specify the generator for this project = Visual Studio 11, Use default native compilers" -> Finish
Then I get an info: Error in configuration process, project files may be invalid
CMake Gui contains following informations:
Name: CMAKE_INSTALL_PREFIX Value C:/Program Files(x86)/projectName
Name: SFML_INCLUDE_DIR Value SFML_INCLUDE_DIR-NOTFOUND
CMake Error at thirdparty/FindSFML.cmake:165 (message):
Could NOT find SFML (missing: SFML_SYSTEM_LIBRARY SFML_WINDOW_LIBRARY
SFML_AUDIO_LIBRARY SFML_NETWORK_LIBRARY SFML_GRAPHICS_LIBRARY)
Call Stack (most recent call first):
CMakeLists.txt:63 (find_package)
I downloaded SFML and set SFML_INCLUDE_DIR (in CMake Gui): C:/OpenGL/SFML-2.1/include/SFML but I still get that error. 2. How to fix that ? What about lib files and dll's ?
Edit1:
I downloaded SFML from the official site
FindSFML.cmake from the project doesn't contain any SFML_ROOT entry, but SFML_INCLUDE_DIR looks like this:
# find the SFML include directory
find_path(SFML_INCLUDE_DIR SFML/Config.hpp
PATH_SUFFIXES include
PATHS
${SFMLDIR}
$ENV{SFMLDIR}
~/Library/Frameworks
/Library/Frameworks
/usr/local/
/usr/
/sw # Fink
/opt/local/ # DarwinPorts
/opt/csw/ # Blastwave
/opt/)
So how to set SFML_ROOT ? Do I need to add some entries (records) to that file ? How it will look like ?
Edit2: A part of the new FindSFML.cmake with a path to SFML (C:/OpenGL/SFML-2.1/)
find_path(SFML_INCLUDE_DIR SFML/Config.hpp
PATH_SUFFIXES include
PATHS
${SFML_ROOT}
$ENV{SFML_ROOT}
C:/OpenGL/SFML-2.1/
~/Library/Frameworks
/Library/Frameworks
/usr/local/
/usr/
/sw # Fink
/opt/local/ # DarwinPorts
/opt/csw/ # Blastwave
/opt/)

First of all, SFML is not CMake standard module, so it would be nice to provide link to sources. I hope you mean this product. Take a look at the FindSFML file:
# If SFML is not installed in a standard path, you can use the SFML_ROOT CMake (or environment) variable
# to tell CMake where SFML is.
So you probably simply need to set SFML_ROOT variable, but not SFML_INCLUDE_DIR.
What about lib files and dll's?
I think this may be helpful:
# By default, the dynamic libraries of SFML will be found. To find the static ones instead,
# you must set the SFML_STATIC_LIBRARIES variable to TRUE before calling find_package(SFML ...).
Can I choose other directory or it should be set to the directory which contains source files: h, cpp etc.
It is highly recommended to use a separate directory.

Related

Qt - How to write a FindXXX.cmake file for a certain Qt library

So I really want to start developing my Qt project inside a different IDE (Clion to be exact). I've written my CMake file for the project. It successfully finds Qt Core, Widgets and other libraries but when it comes to including Qt Charts Cmake throws an error:
CMake Error at CMakeLists.txt:44 (find_package):
By not providing "FindQt5Charts.cmake" in CMAKE_MODULE_PATH this project
has asked CMake to find a package configuration file provided by
"Qt5Charts", but CMake did not find one.
This error is successfully removed when I add by hand a "FindQt5Charts.cmake" file in my CLion>bin>Cmake>share>modules (where FindQt.cmake and othere search package files are) but as of now this file is empty.
The Cmake compiles successfully but since it hasn't found the library I'm looking for, my project won't compile. I need your help to write "FindQt5Charts.cmake" file because I'm not 100% sure of its syntax.
NOTE: Qt Charts is installed and its folder could be found in Qt's installation directory. I just need the code for the FindQt5Charts.cmake.
Here's a reference to the FindQt.cmake file
Here is how the beggining of my project's cmake looks:
#Pull needed header files generated by QT first
set(QT_GENERATED qtGenerated)
add_custom_target(${QT_GENERATED})
#Get all header files in the directory
file(GLOB QT_GEN_HEADERS ${QT_BIN}/*.h)
#Copy them to the project dir
foreach (QT_GEN_HEADERS ${QT_GEN_HEADERS})
add_custom_command(TARGET ${QT_GENERATED} PRE_BUILD COMMAND
${CMAKE_COMMAND} -E copy_if_different
${QT_GEN_HEADERS} ${CMAKE_SOURCE_DIR})
endforeach ()
# Find the Qt libraries
foreach (QT_LIBRARIES_REQUIRED ${QT_LIBRARIES_REQUIRED})
find_package(${QT_LIBRARIES_REQUIRED} REQUIRED)
endforeach ()

Link to static library by cmake

I have a project C++ using libnuma library. Because I don't have permission to install libnuma in the root system, so I have to install it in folder of user: /home/khangtg/opt. This folder contains 2 main folders:
Folder include contains: numacompat1.h, numa.h, numaif.h
Folder lib contains: libnuma.a, libnuma.la, libnuma.so, libnuma.so.1, libnuma.so.1.0.0
Now, I have a file .cpp include libnuma library:
#include <numa.h>
and I build the project by file CMakeLists.txt with content:
add_library (common Bigraph.cpp AdjList.cpp Vocab.cpp NumaArray.cpp clock.cpp)
set (LINK_LIBS ${LINK_LIBS} common gflags numa )
add_executable (warplda main.cpp lda.cpp warplda.cpp)
add_executable (format format.cpp)
target_link_libraries (warplda ${LINK_LIBS})
target_link_libraries (format ${LINK_LIBS})
After run cmake command, I get some error that is "can not include numa.h".
So, how can I fix this error and build the project by cmake. Many thanks!
you want to set the link_directories to include the directory of the libraries. More can be found in the cmake docs. This tells the linker where to look for the libraries.
It should probably look something like this
link_directories(/home/khangtg/opt/lib)
Also add the include directories command from this documentation.
This will look like this
include_directories(/home/khangtg/opt/include)
This might be useful to add to your cmake build file:
include_directories("/home/khangtg/opt/include")
From: cmake tutorial
You may also want to change the include to :
#include "numa.h"

Finding a directory in CMake

The problem:
I want to add the boost numeric bindings as an include directory in my build. This is typically compiled as:
c++ -I/where/you/want/to/install/it/include/boost-numeric-bindings
All of the header files I reference from my program are all relative to this directory, so in CMake I want to find this directory (wherever it is installed on the parent system) and add it to the include_directories.
What I'm looking for:
Something like this:
find_directory(BNB_INCLUDE_DIR boost-numeric-bindings)
include_directories(${BNB_INCLUDE_DIR})
But the find_directory command does not exist. Am I missing something here?
What I've tried:
I've tried:
find_path(BNB_INCLUDE_DIR boost/numeric/bindings/traits/ublas_vector.hpp)
include_directories(${BNB_INCLUDE_DIR})
(which is the first file I need from the library) but this gives me the full path to the file and not the path to the directory containing the entire prefix to the file specified in the command.
See this answer for information on how to write a cmake Find file. As an example, here is one that I wrote for the lm-sensors library:
# - Try to find the LM_SENSORS library.
#
# The following are set after configuration is done:
# LM_SENSORS_FOUND
# LM_SENSORS_INCLUDE_DIRS
# LM_SENSORS_LIBRARY_DIRS
# LM_SENSORS_LIBRARIES
find_path(LM_SENSORS_INCLUDE_DIR NAMES sensors/sensors.h)
find_library(LM_SENSORS_LIBRARY NAMES libsensors sensors)
message("LM_SENSORS include dir = ${LM_SENSORS_INCLUDE_DIR}")
message("LM_SENSORS lib = ${LM_SENSORS_LIBRARY}")
set(LM_SENSORS_LIBRARIES ${LM_SENSORS_LIBRARY})
set(LM_SENSORS_INCLUDE_DIRS ${LM_SENSORS_INCLUDE_DIR})
include(FindPackageHandleStandardArgs)
# Handle the QUIETLY and REQUIRED arguments and set the LM_SENSORS_FOUND to TRUE
# if all listed variables are TRUE
find_package_handle_standard_args(LM_SENSORS DEFAULT_MSG
LM_SENSORS_LIBRARY LM_SENSORS_INCLUDE_DIR)
mark_as_advanced(LM_SENSORS_INCLUDE_DIR LM_SENSORS_LIBRARY)
Change the above to match your library (boost-numeric-bindings), name the file Findboost-numeric-bindings.cmake, and put it in your cmake module dir (or create one of these in your source tree).
Then in your CMakeLists.txt file, do this:
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} your_cmake_module_dir)
find_package (boost-numeric-bindings REQUIRED)
include_directories(${BOOST_NUMERIC_BINDINGS_INCLUDE_DIR})
Then, assuming you don't have the library installed in a standard location, run cmake as follows:
cmake -D CMAKE_PREFIX_PATH:STRING="/where/you/have/installed/it/" <source path>
Edit
Make sure you have defined a project before you call find_path or find_package. Otherwise CMAKE_SYSTEM_INCLUDE_PATH will not be set. For example:
find_path (BOOST_STATE_HPP boost/statechart/state.hpp)
message ("CMAKE_FIND_ROOT_PATH=${CMAKE_FIND_ROOT_PATH}")
message ("CMAKE_SYSTEM_INCLUDE_PATH=${CMAKE_SYSTEM_INCLUDE_PATH}")
message ("CMAKE_SYSTEM_FRAMEWORK_PATH=${CMAKE_SYSTEM_FRAMEWORK_PATH}")
message ("CMAKE_PREFIX_PATH=${CMAKE_PREFIX_PATH}")
message ("BOOST_STATE_HPP=${BOOST_STATE_HPP}")
project (my_project)
will result in the following cmake output:
CMAKE_FIND_ROOT_PATH=
CMAKE_SYSTEM_INCLUDE_PATH=
CMAKE_SYSTEM_FRAMEWORK_PATH=
CMAKE_PREFIX_PATH=
BOOST_STATE_HPP=BOOST_STATE_HPP-NOTFOUND
whereas this:
project (my_project)
find_path (BOOST_STATE_HPP boost/statechart/state.hpp)
message ("CMAKE_FIND_ROOT_PATH=${CMAKE_FIND_ROOT_PATH}")
message ("CMAKE_SYSTEM_INCLUDE_PATH=${CMAKE_SYSTEM_INCLUDE_PATH}")
message ("CMAKE_SYSTEM_FRAMEWORK_PATH=${CMAKE_SYSTEM_FRAMEWORK_PATH}")
message ("CMAKE_PREFIX_PATH=${CMAKE_PREFIX_PATH}")
message ("BOOST_STATE_HPP=${BOOST_STATE_HPP}")
results in sucessfully finding state.hpp and setting BOOST_STATE_HPP to /usr/include, as you desire:
CMAKE_FIND_ROOT_PATH=
CMAKE_SYSTEM_INCLUDE_PATH=/usr/include/w32api;/usr/X11R6/include;/usr/include/X11;/usr/pkg/include;/opt/csw/include;/opt/include;/usr/openwin/include
CMAKE_SYSTEM_FRAMEWORK_PATH=
CMAKE_PREFIX_PATH=
BOOST_STATE_HPP=/usr/include

ITK installation and sample program

I am new to ITK and I did the following step to install ITK and use it to programme in VS2010
Downloaded ITK 4.3.1 and build it with CMAKE
The build was successful and I had a lib->Debug folder containing the libs.
Added the bin folder path to environmental vairable path.
Following is my simple code...
#include <iostream>
#include <Core/Common/include/itkImage.h>
using namespace itk;
using namespace std;
int main()
{
return 0;
}
the above code returns
Cannot open include file: 'itkConfigure.h'
I tried searching for that header but no luck. However in C:\InsightToolkit-4.3.1\Modules\Core\Common\src I found itkConfigure.h.in file. I am really clueless about how to go about this .in file. Any help is most welcome..
The easiest way to set up your project is to use CMake again. Try creating a project with just a CMakeLists.txt and main.cpp. The CMakeLists.txt should have something like:
cmake_minimum_required(VERSION 2.8 FATAL_ERROR)
project(ItkTest)
find_package(ITK REQUIRED)
include(${ITK_USE_FILE})
add_executable(MyTest main.cpp)
target_link_libraries(MyTest ITKCommon)
So say you create these 2 files in a dir called ItkProject, then from a Visual Studio Command Prompt just do:
cd <path to ItkProject>
mkdir build
cd build
cmake .. -DITK_DIR="<path to build dir of ITK>"
The <path to build dir of ITK> is where you ran CMake from to configure the ITK project. It will contain the ITK.sln file, but critically it should also contain a file called ITKConfig.cmake. It is this file which is searched for in the cmake command find_package(ITK REQUIRED) - if CMake can't find it the configuring will fail.
Once that's been found, it sets a bunch of CMake variables which you can then use in your own CMakeLists.txt, including ITK_USE_FILE.
When you then invoke include(${ITK_USE_FILE}), this goes on to set up things like your includes paths, library search paths, and compiler flags. The path <path to ItkProject>/Core/Common/include will be added to the includes dirs, so in your main.cpp, you just need to do:
#include <Core/Common/include/itkImage.h>
#include "itkImage.h"
Anyway, the end result after running CMake should be solution file <path to ItkProject>\build\ItkTest.sln which is set up ready to use ITK.
I checked \ItkConfig.cmake and paths defined there should match physical paths, this is the case if ITK build has been untouched (directory wasn't renamed).
# The ITK source tree.
# For backward compatibility issues we still need to define this variable, although
# it is highly probable that it will cause more harm than being useful.
# Use ITK_INCLUDE_DIRS instead, since ITK_SOURCE_DIR may point to non-existent directory
IF(NOT ITK_LEGACY_REMOVE)
SET(ITK_SOURCE_DIR "C:/ITK320")
ENDIF(NOT ITK_LEGACY_REMOVE)
# The ITK include file directories.
SET(ITK_INCLUDE_DIRS "C:/ITK320-build;C:/ITK320/Code/Algorithms;C:/ITK320/Code/BasicFilters;C:/ITK320/Code/Common;C:/ITK320/Code/Numerics;C:/ITK320/Code/IO;C:/ITK320/Code/Numerics/FEM;C:/ITK320/Code/Numerics/NeuralNetworks;C:/ITK320/Code/SpatialObject;C:/ITK320/Utilities/MetaIO;C:/ITK320/Utilities/NrrdIO;C:/ITK320-build/Utilities/NrrdIO;C:/ITK320/Utilities/DICOMParser;C:/ITK320-build/Utilities/DICOMParser;C:/ITK320-build/Utilities/expat;C:/ITK320/Utilities/expat;C:/ITK320/Utilities/nifti/niftilib;C:/ITK320/Utilities/nifti/znzlib;C:/ITK320/Utilities/itkExtHdrs;C:/ITK320-build/Utilities;C:/ITK320/Utilities;C:/ITK320/Code/Numerics/Statistics;C:/ITK320/Utilities/vxl/v3p/netlib;C:/ITK320/Utilities/vxl/vcl;C:/ITK320/Utilities/vxl/core;C:/ITK320-build/Utilities/vxl/v3p/netlib;C:/ITK320-build/Utilities/vxl/vcl;C:/ITK320-build/Utilities/vxl/core;C:/ITK320-build/Utilities/gdcm;C:/ITK320/Utilities/gdcm/src")
# The ITK library directories.
SET(ITK_LIBRARY_DIRS "C:/ITK320-build/bin")

cmake - find_library - custom library location

I'm currently trying to get CMake running for my project (on windows). I want to use a custom location where all libraries are installed. To inform CMake about that path I tried to do that:
set(CMAKE_PREFIX_PATH D:/develop/cmake/libs)
But when I try to find the library with
find_library(CURL_LIBRARY NAMES curl curllib libcurl_imp curllib_static)
CMake can't find it.
When I set my prefix path to
set(CMAKE_PREFIX_PATH D:/develop/cmake/libs/curl)
... the library is located.
So my question is:
How can I configure CMake properly to work with a directory structore at a custom location which looks like that:
D:/develop/cmake/libs/
-> libA
-> include
-> lib
-> libB
-> include
-> lib
-> ...
-> include
-> lib
In "include" lie the public headers and in "lib" are the compiled libraries.
edit:
The current workaround for me is, to do this before i search for libraries:
set(CUSTOM_LIBRARY_PATH D:/develop/cmake/libs)
file(GLOB sub-dir ${CUSTOM_LIBRARY_PATH}/*)
foreach(dir ${sub-dir})
if(IS_DIRECTORY ${dir})
set(CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH};${dir})
endif()
endforeach()
But that way the default module for boost wont find it until it because the directory structore of boost is a bit different.
boost -> include -> boost-1_50 -> *.hpp
When I move the content if "boost-1_50" to "include" the library can be found but that way it's not possible to handle multiple versions right?
The simplest solution may be to add HINTS to each find_* request.
For example:
find_library(CURL_LIBRARY
NAMES curl curllib libcurl_imp curllib_static
HINTS "${CMAKE_PREFIX_PATH}/curl/lib"
)
For Boost I would strongly recommend using the FindBoost standard module and setting the BOOST_DIR variable to point to your Boost libraries.
I saw that two people put that question to their favorites so I will try to answer the solution which works for me:
Instead of using find modules I'm writing configuration files for all libraries which are installed. Those files are extremly simple and can also be used to set non-standard variables. CMake will (at least on windows) search for those configuration files in
CMAKE_PREFIX_PATH/<<package_name>>-<<version>>/<<package_name>>-config.cmake
(which can be set through an environment variable).
So for example the boost configuration is in the path
CMAKE_PREFIX_PATH/boost-1_50/boost-config.cmake
In that configuration you can set variables. My config file for boost looks like that:
set(boost_INCLUDE_DIRS ${boost_DIR}/include)
set(boost_LIBRARY_DIR ${boost_DIR}/lib)
foreach(component ${boost_FIND_COMPONENTS})
set(boost_LIBRARIES ${boost_LIBRARIES} debug ${boost_LIBRARY_DIR}/libboost_${component}-vc110-mt-gd-1_50.lib)
set(boost_LIBRARIES ${boost_LIBRARIES} optimized ${boost_LIBRARY_DIR}/libboost_${component}-vc110-mt-1_50.lib)
endforeach()
add_definitions( -D_WIN32_WINNT=0x0501 )
Pretty straight forward + it's possible to shrink the size of the config files even more when you write some helper functions. The only issue I have with this setup is that I havn't found a way to give config files a priority over find modules - so you need to remove the find modules.
Hope this this is helpful for other people.
Use CMAKE_PREFIX_PATH by adding multiple paths (separated by semicolons and no white spaces). You can set it as an environmental variable to avoid having absolute paths in your cmake configuration files
Notice that cmake will look for config file in any of the following folders
where is any of the path in CMAKE_PREFIX_PATH and name is the name of the library you are looking for
<prefix>/ (W)
<prefix>/(cmake|CMake)/ (W)
<prefix>/<name>*/ (W)
<prefix>/<name>*/(cmake|CMake)/ (W)
<prefix>/(lib/<arch>|lib|share)/cmake/<name>*/ (U)
<prefix>/(lib/<arch>|lib|share)/<name>*/ (U)
<prefix>/(lib/<arch>|lib|share)/<name>*/(cmake|CMake)/ (U)
In your case you need to add to CMAKE_PREFIX_PATH the following two paths:
D:/develop/cmake/libs/libA;D:/develop/cmake/libB
There is no way to automatically set CMAKE_PREFIX_PATH in a way you want. I see following ways to solve this problem:
Put all libraries files in the same dir. That is, include/ would contain headers for all libs, lib/ - binaries, etc. FYI, this is common layout for most UNIX-like systems.
Set global environment variable CMAKE_PREFIX_PATH to D:/develop/cmake/libs/libA;D:/develop/cmake/libs/libB;.... When you run CMake, it would aautomatically pick up this env var and populate it's own CMAKE_PREFIX_PATH.
Write a wrapper .bat script, which would call cmake command with -D CMAKE_PREFIX_PATH=... argument.
You have one extra level of nesting.
CMAKE will search under $CMAKE_PREFIX_PATH/include for headers and $CMAKE_PREFIX_PATH/libs for libraries.
From CMAKE documentation:
For each path in the CMAKE_PREFIX_PATH list, CMake will check
"PATH/include" and "PATH" when FIND_PATH() is called, "PATH/bin" and
"PATH" when FIND_PROGRAM() is called, and "PATH/lib and "PATH" when
FIND_LIBRARY() is called.
I've encountered a similar scenario. I solved it by adding in this following code just before find_library():
set(CMAKE_PREFIX_PATH /the/custom/path/to/your/lib/)
then it can find the library location.