Using cmake for a project with sub/external projects/dependencies - c++

I am actually imroving my c++ skills with a project that uses PocoProject as a framework for supplying a simple rest webserver and json parsing as well as a mongodb driver.
I am compiling my project with cmake/make
my directory structure is:
root
- pocoproject
- helloworld.cpp
- CMakeLists.txt
To test cmake, I have a simple cpp file (taken from the poco examples) that starts a http-server. the includes are the following:
#include "Poco/Net/HTTPServer.h"
#include "Poco/Net/HTTPRequestHandler.h"
...
#include "Poco/Util/HelpFormatter.h"
#include <iostream>
My CMakeLists.txt look like:
cmake_minimum_required (VERSION 2.6)
project (Hello)
add_executable(Hello helloworld.cpp)
Question:
How do I add the needed libraries from pocoproject to to my executable? How do I reference the headers correctly?

You need let your CMake project know where to look for the dependencies, such as Poco. You need to set the variable CMAKE_PREFIX_PATH. It can be done with cmake-gui or on the command line:
cmake ... -DCMAKE_PREFIX_PATH=<path> ...
The <path> is where you copied or installed the Poco library, so the Poco headers will have paths like <path>/include/Poco/AbstractCache.h, etc..., libraries like <path>/lib/libPocoFoundation.* and most importantly, the config-module must be found at <path>/lib/cmake/Poco/PocoConfig.cmake.
In your CMakeLists.txt you need to find the Poco package with
find_package(Poco REQUIRED Foundation Util Net)
and link to it with
target_link_libraries(Hello Poco::Foundation Poco::Util Poco::Net)

Related

Facing problems in my first time handling CMake, Third party(header only) libraries

I want to use the following library
https://github.com/gmeuli/caterpillar
It's documentation says that it's a header-only library, and that I should "directly integrate it into my source files with #include <caterpillar/caterpillar.h>." It also depends on a few other libraries, one of which I need to use directly as well.
So far I have done the following:
create cmake project to make an 'executable' (with the vscode extension)
created a 'lib' folder, inside which I did
git clone https://github.com/gmeuli/caterpillar
Then, I did include_directories(lib) in my cmake file.
But #include <caterpillar/caterpillar.h> doesn't quite work in my singular main.cpp file.
I played around with various CMake functions, and it either gave the error "No such file or directory" regarding caterpillar/caterpillar.h itself, or it gave "cannot open source file... dependent of caterpillar/caterpillar.h" depending on how I messed with the cmake file.
For reference:
cat ~/project/main.cpp
#include <caterpillar/caterpillar.hpp>
#include <lorina/lorina.hpp> //how do I include this ? it's in the lib folder of caterpillar itself, or do I need to have a copy of it in my lib folder too
int main()
{
// stuff in lorina:: namespace
// stuff in caterpillar:: namespace
return 0;
}
cat ~/project/CMakeLists.txt
include_directories(lib)
//... rest is stuff like CXX standard, etc etc
tree ~/project
main.cpp
lib/
caterpillar/
build/
cmake generated stuff
CMakeLists.txt
Firstly, modern cmake recommends target_include_directories() instead of old include_directories() for better scope management.
Actually <caterpillar/caterpillar.hpp> is not in $PROJECT_SOURCE_DIR/lib directory. That's why your code not works.
CMakeLists example:
cmake_minimum_required(VERSION 3.22)
project(myproject)
set(CMAKE_CXX_STANDARD 17)
add_executable(my_project main.cpp)
target_include_directories(my_project PRIVATE ${PROJECT_SOURCE_DIR}/lib/caterpillar/include)
# project_src_dir/lib/catepillar/include/ is the directory where you find the headers like <catepillar/catepillar.hpp>
target_include_directories(my_project PRIVATE ${PROJECT_SOURCE_DIR}/lib/caterpillar/lib/lorina)
caterpillar's document describes how to include their headers in a traditional style, assuming the readers could understand this and decide where to put the headers themselves. (which means you don't need the whole git repo but only the "include" dir.)
For this specific problem, the library has provided a detailed CMakeLists.txt for users to include:
cmake_minimum_required(VERSION 3.22)
project(my_project)
set(CMAKE_CXX_STANDARD 17)
add_subdirectory(lib/caterpillar)
# this works because "project_src_dir/lib/catepillar/CMakeLists.txt" exists.
add_executable(my_project main.cpp)
target_link_libraries(my_project PRIVATE caterpillar)
# you need to tell cmake to add all catepillar settings into your project

cmake + cpp: No such file or directory

I've I'm trying to build this "Hello World" wxWidgets example on Linux, using the following cmake script:
cmake_minimum_required (VERSION 2.6)
project (wxL)
find_package(wxWidgets 3.0.0 REQUIRED
COMPONENTS base core net xml html adv qa richtext
)
file(GLOB SOURCES "src/*.cpp")
add_executable(wxL ${SOURCES})
Building the project yields this error:
src/wxL.cpp:3:10: fatal error: wx/wxprec.h: No such file or directory
The file specified in the include, wx/wxprec.h can be found on disk at this location:
/usr/include/wx-3.0/wx/wxprec.h
Furthermore, another program that I have built from source includes the same file (also using cmake) and builds just fine.
So, how do I use cmake to tell the compiler that the file should be included from somewhere in the system directories?
I know I'm missing something basic, but I can't figure out what.
Although you've found the package, your executable does not know anything about it.
For the executable to compile correctly, it needs to find header files for your package together with the .so / .a files. Following example should get you started:
include_directories(${wxWidgets_INCLUDE_DIRS})
add_executable(wxL <add-source-files-here>)
target_link_libraries(wxL ${wxWidgets_LIBRARIES}) // links wxWidgets libraries to your executable
Please note that using glob is not a recommended way of adding source files to your project.

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"

Setup Boost in Clion

How to use Boost library in Clion with MinGW ? I have downloaded and unzipped boost_1_60_0.zip to C:\boost_1_60_0. What am I supposed to do now ? Do I have to install something ? Here is my CMakeLists.txt:
cmake_minimum_required(VERSION 3.3)
project(server_client)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -s -O3")
set(CMAKE_EXE_LINKER_FLAGS -static)
set(BOOST_ROOT "C:/boost_1_60_0")
set(BOOSTROOT "C:/boost_1_60_0")
find_package(Boost 1.60.0)
if(NOT Boost_FOUND)
message(FATAL_ERROR "Could not find boost!")
endif()
set(SOURCE_FILES chat_server.cpp)
add_executable(server_client ${SOURCE_FILES})
Can not find Boost:
I use MinGW distro by Stephan T. Lavavej with Boost libraries prebuilt.
In my cmaklist.txt I added this
set(Boost_INCLUDE_DIR c:/mingw/include/)
set(Boost_LIBRARY_DIR c:/mingw/lib/)
find_package(Boost COMPONENTS system filesystem REQUIRED)
include_directories(${Boost_INCLUDE_DIR})
This post help me get it going. How to include external library (boost) into CLion C++ project with CMake?
Here's example project for CLion that uses Boost's regex library. It references to this tutorial.
Goal: with CLion create .exe that process jayne.txt as shown in Boost's tutorial.
My example revolves around building Boost Library Binary with GCC, configuring project in CLion and using CMake. It's quite expressive, maybe even an overkill, but I believe you can adapt. On the other hand I'll try to make project itself as system independent as its possible.
Configuration:
OS: Windows 8.1
CLion: 2018.2.4
Boost: 1.68.0
compiler: GCC-6.3.0 (provided by MinGW)
MinGW was configured according to its instructions and JetBrains's suggestions. (I downloaded setup for MinGW 14/10/2018 if that matters.)
A word about tools structure
I decided to create following structure for Boost and things aroung it:
D:\
SDK\
boost\
boost_1_68_0\ # untouched Boost root
boost\
rst.css
...other directories and files...
1_68_0\
build\ # dir for Boost.Build, b2.exe
buildDir\ # intermediate dir for creating libraries
stageDir\ # dir for libraries
lib\
MinGW\
bin\
...other directories...
I left Boost root untouched -- I didn't create any additional directories. This separates Boost sources from created tools and libraries so I can show how to specify these directories explicitly.
Obtain Boost Library Binary
I decided to build libraries from source with GCC.
Download and unpack Boost ("D:\SDK\boost\boost_1_68_0");
Build libraries (5.2):
Open command prompt at \tools\build of Boost root ("D:\SDK\boost\boost_1_68_0\tools\build")
Run bootstrap.bat
Run b2 install --prefix="D:\SDK\boost\1_68_0\build" --toolset=gcc-6.3.0. This creates b2.exe under "D:\SDK\boost\1_68_0\build\bin"
Move command prompt to Boost root (cd "D:\SDK\boost\boost_1_68_0")
(You can consider using "D:\SDK\boost\1_68_0\build\bin\b2.exe --show-directories". It's worth to specify libraries to build (--with-library-name) in the following command, because this step can take a while.) Run "D:\SDK\boost\1_68_0\build\bin\b2" --build-dir="D:\SDK\boost\1_68_0\buildDir" toolset=gcc-6.3.0 --build-type=complete stage --stagedir="D:\SDK\boost\1_68_0\stageDir" --with-regex. It creates following files under D:\SDK\boost\1_68_0\stageDir\lib directory:
libboost_regex-mgw63-mt-d-x32-1_68.a
libboost_regex-mgw63-mt-d-x32-1_68.dll
libboost_regex-mgw63-mt-d-x32-1_68.dll.a
libboost_regex-mgw63-mt-sd-x32-1_68.a
libboost_regex-mgw63-mt-s-x32-1_68.a
libboost_regex-mgw63-mt-x32-1_68.a
libboost_regex-mgw63-mt-x32-1_68.dll
libboost_regex-mgw63-mt-x32-1_68.dll.a
CMake looks for files with specific names in library folder, so be sure to (copy and) change name for one of .a files there. For this example, I changed libboost_regex-mgw63-mt-x32-1_68.a to boost_regex.a.
Create CLion project
Create a new project (for this example its name is CLionBoostRegex) and put content to main.cpp (6):
#include <boost/regex.hpp>
#include <iostream>
#include <string>
int main()
{
std::string line;
boost::regex pat( "^Subject: (Re: |Aw: )*(.*)" );
while (std::cin)
{
std::getline(std::cin, line);
boost::smatch matches;
if (boost::regex_match(line, matches, pat))
std::cout << matches[2] << std::endl;
}
}
Configure CLion
Go to (on Windows) File -> Settings -> Build, Execution, Deployment -> CMake, and in CMake options add path to Boost root directory with -DBOOST_ROOT=, i.e.: -DBOOST_ROOT="D:\SDK\boost\boost_1_68_0". If directory with built libraries is placed outside Boost root, add it with -DBOOST_LIBRARYDIR=, i.e.: -DBOOST_LIBRARYDIR="D:\SDK\boost\1_68_0\stageDir\lib". Commands are space separated.
Decide if you want static or dynamic linking.
Option 1: Static linking
For static linking your CMakeLists.txt should look like this:
cmake_minimum_required(VERSION 3.12)
project(CLionBoostRegex)
set(CMAKE_CXX_STANDARD 98)
find_package(Boost REQUIRED COMPONENTS regex)
include_directories(${Boost_INCLUDE_DIRS})
add_executable(CLionBoostRegex main.cpp)
target_link_libraries(CLionBoostRegex -static)
target_link_libraries(CLionBoostRegex ${Boost_LIBRARIES})
Option 2: Dynamic linking
CMakeLists.txt should look like for static linking, but remove target_link_libraries(CLionBoostRegex -static) line.
After building your project make sure to copy .dll library to directory with executable (libboost_regex-mgw63-mt-x32-1_68.dll) along with libstdc++-6.dll from MinGW\bin directory (D:\SDK\MinGW\bin) (or consider including target_link_libraries(CLionBoostRegex -static-libstdc++) line in CMakeLists.txt or add -DCMAKE_CXX_FLAGS="-static-libstdc++" to CMake options in settings).
Run your program (6.4)
Build your target (it creates cmake-build-debug\ directory with default config) (if you picked dynamic linking make sure to add necessary .dlls)
In directory with your executable create jayne.txt file with following content:
To: George Shmidlap
From: Rita Marlowe
Subject: Will Success Spoil Rock Hunter?
---
See subject.
Open command prompt there
Run CLionBoostRegex.exe < jayne.txt
Program should output Will Success Spoil Rock Hunter? as shown in tutorial.
Notes
Changing name for an .a library and choosing -static linking causes the least effort afterwards - you won't have to copy any additional libraries at the price of bigger executable size. When executable size is more important, you can change name for .dll library in Boost libraries directory instead and then copy missing .dlls for your .exe (i.e.: libboost_regex-mgw63-mt-x32-1_68.dll and libstdc++-6.dll).
You can include set(Boost_DEBUG ON) line in your CMakeLists.txt or -DBoost_DEBUG=1 to CMake options to get some precious info.
I used other questions to write this post, most notably: 1, 2, 3, 4.

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")