Minimal protobuf c++ installation for CMake use - cmake

I'm trying to use the CMake functions protobuf_generate in one of my projects. However, I'd like to the build as lightweight as possible. If at all possible I'd like to do this without having to compile protobuf's source code, or install some package on my (windows) machine.
Is there a way to just download binaries and headers and tell CMake: "Here is everything you need", so I can swap new proto versions whenever I feel like?

# CMakeList.txt : Top-level CMake project file, do global configuration
# and include sub-projects here.
#
cmake_minimum_required (VERSION 3.5)
project ("CMakeProject1")
set(TARGET_NAME CMakeProject1)
SET(PROTOBUF_INCLUDE_DIR "/path/to/include")
SET(PROTOBUF_LIBRARY "/path/to/libprotobuf.lib")
SET(PROTOBUF_PROTOC_EXECUTABLE "/path/to/protoc.exe")
find_package(Protobuf)
protobuf_generate_cpp(PROTO_SRCS PROTO_HDRS path/to/some_object.proto)
add_library(${TARGET_NAME} STATIC ${PROTO_SRCS} ${PROTO_HDRS})

Related

Is it possible to create or access libraries globally with cmake?

My project is located in this filepath:
C:\Users\zaina\OneDrive\foo_directory\bar_projectname
The libraries and git repositories, which I want to use globally, are located in this file path:
C:\dev\github\foobar
For example This repository is about controlling Tello drone with c++ language, and I cloned this
I used Cmake GUI to configure the build and Visual Studio to build the libraries, but I simply can't include it in my project by invoking:
#include <tello/tello.hpp>
So there must be something that might help.
I tried git submodules and it worked fine, but it only works for a single project and not globally.
So I was wondering that is there a possibility to set a cloned repository as a global library or create one. If it is, then how?
I tried this as my CMakeLists.txt:
project(foo)
# Setup testing
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/cmake)
enable_testing()
add_executable(foo main.cpp)
target_include_directories(foo PRIVATE ${tello_SOURCE_DIR}/src)
target_link_libraries(tello_test PRIVATE tello)
But that did not work, because my program can't find the tello header files.

Why my <package>-config.cmake have <package>_include_dir and <package>_librairies empty

I am trying to make a cross-platform CMake for my project (Windows and Linux).
I need to use external libraries (yaml-cpp). On Linux, I just had to do an apt get and use find_package. But on Windows, I need to append the CMAKE_MODULE_PATH in order for my program to find the yaml-cpp-config.cmake.
So I start by installing yaml-cpp (https://github.com/jbeder/yaml-cpp) with CMake GUI 3.16 and mingw32 (mingw32-make install).
I have tried the library on a hello world project, and it works fine.
cmake_minimum_required(VERSION 3.1)
project (yaml_test)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
message (STATUS "Yaml-cpp include = $ENV{YAML_CPP_INCLUDE_DIR}")
message (STATUS "Yaml-cpp library = $ENV{YAML_CPP_LIBRARIES}")
include_directories ($ENV{YAML_CPP_INCLUDE_DIR})
add_executable(yaml_test main.cpp)
target_link_libraries(yaml_test $ENV{YAML_CPP_LIBRARIES})
But now, I want to include the library in my project and use find_package. But the yaml-cpp-config.cmake looks like this:
# - Config file for the yaml-cpp package
# It defines the following variables
# YAML_CPP_INCLUDE_DIR - include directory
# YAML_CPP_LIBRARIES - libraries to link against
# Compute paths
get_filename_component(YAML_CPP_CMAKE_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH)
set(YAML_CPP_INCLUDE_DIR "")
# Our library dependencies (contains definitions for IMPORTED targets)
include("${YAML_CPP_CMAKE_DIR}/yaml-cpp-targets.cmake")
# These are IMPORTED targets created by yaml-cpp-targets.cmake
set(YAML_CPP_LIBRARIES "")
The YAML_CPP_INCLUDE_DIR and YAML_CPP_LIBRARIES variables are empty, and even if CMake found yaml-cpp-config.cmake, It doesn't work. So what do I have missing in the installation of yaml-cpp? Should I have set the paths by hand?
The absence of definition of YAML_CPP_INCLUDE_DIR and YAML_CPP_LIBRARIES variables is the issue with the yaml-cpp project which is already reported here.
Instead of variables described in this config file, use target yaml-cpp:
add_executable(yaml_test main.cpp)
# This provides both include directories and libraries.
target_link_libraries(yaml_test yaml-cpp)
Linking with an IMPORTED target (yaml-cpp in this case) is known as CMake "modern way".

CMake find protobuf compiled from source

I am trying to build a project that depends on Google Protocol Buffers compiled from source. My project should be platform independent and also should support cross-compilation, which is the reason that i prefer to use a locally built protobuf. However I would prefer not to include the whole library as a subproject as it would take too much to build.
My simplified CMakeLists.txt is:
cmake_minimum_required(VERSION 3.5)
project(sample-protobuf)
# find a boost install with the libraries filesystem and system
find_package(Protobuf REQUIRED)
set(SOURCES
main.cpp
)
add_executable(sample
${SOURCES}
)
target_link_libraries(sample
PRIVATE
protobuf::libprotobuf
)
I invoke CMake on Linux as:
cmake -DCMAKE_PREFIX_PATH=/path/to/built/protobuf/ ..
but it does not find the library and I get the following message:
Could not find a package configuration file provided by "Protobuf" with any
of the following names:
ProtobufConfig.cmake
protobuf-config.cmake
Add the installation prefix of "Protobuf" to CMAKE_PREFIX_PATH or set
"Protobuf_DIR" to a directory containing one of the above files. If
"Protobuf" provides a separate development package or SDK, be sure it has
been installed.
On Windows this procedure works.
I built the library on Linux using the suggested approach, which is not with CMake but with autotools.
What should I do differently?
cd protobuf/cmake
mkdir build
cd build
cmake....
make...
sudo make install

Making a CMake library accessible by other CMake packages automatically

I have one project that produces a library:
project (myCoolLibrary)
ADD_LIBRARY(my_cool_library SHARED ${mysources_SRC})
And another project that should be using this library:
find_package (myCoolLibrary REQUIRED)
INCLUDE_DIRECTORIES("${myCoolLibrary_INCLUDE_DIRS}" )
add_executable(myCoolExe ${my_sources_SRC} )
TARGET_LINK_LIBRARIES(myCoolExe ${myCoolLibrary_LIBRARIES} )
Is there a way that I can change the first file so that the second file works automatically? That by running CMake on the first file and then running make on the output, then running CMake on the second file, CMake is able to find the package?
An answer where I just give the address of where the first project is built to the second package is also acceptable.
Taking the code found in a blog post by #daniperez - Use CMake-enabled libraries in your CMake project (III) - I've come up with the following minimal solution:
myCoolLibrary/CMakeLists.txt
cmake_minimum_required(VERSION 3.3)
project(myCoolLibrary)
function(my_export_target _target _include_dir)
file(
WRITE "${CMAKE_CURRENT_BINARY_DIR}/${_target}Config.cmake"
"
include(\"\$\{CMAKE_CURRENT_LIST_DIR\}/${_target}Targets.cmake\")
set_property(
TARGET ${_target}
APPEND PROPERTY
INTERFACE_INCLUDE_DIRECTORIES \"${_include_dir}\"
)
"
)
export(TARGETS ${_target} FILE "${CMAKE_CURRENT_BINARY_DIR}/${_target}Targets.cmake")
# NOTE: The following call can pollute your PC's CMake package registry
# See comments/alternatives below
export(PACKAGE ${_target})
endfunction(my_export_target)
...
add_library(${PROJECT_NAME} SHARED ${mysources_SRC})
my_export_target(${PROJECT_NAME} "${CMAKE_CURRENT_SOURCE_DIR}")
myCoolExe/CMakeLists.txt
cmake_minimum_required(VERSION 3.3)
project(myCoolExe)
find_package(myCoolLibrary REQUIRED)
...
add_executable(${PROJECT_NAME} ${my_sources_SRC})
target_link_libraries(${PROJECT_NAME} myCoolLibrary)
To make it reusable I have packed everything into my_export_target(). And I'm friend of self-propagating properties like INTERFACE_INCLUDE_DIRECTORIES.
As commented by #ruslo, using export(PACKAGE ...) can pollute your package registry. So alternatively you can:
Write the target configuration files directly to some dedicated place specific for a certain toolchain
See e.g. How to install your custom CMake-Find module and 0003659: FIND_PACKAGE command improvements.
Set CMAKE_MODULE_PATH via the second project's CMake command line (injecting the search path(s) from the outside). If you are building the two projects anyway with a build script, then this is the most direct way to propagate the module search path(s).
Additional References
export()
CMake/Tutorials/Package Registry
Unable to find Eigen3 with CMake
How to instruct CMake to use the build architecture compiler

Clion, cMake and POCO

I'm a new guy to c++ and cmake here. I decided to test out cLion and cMake. I'm trying to write a simple email client for the command line. Other sources told me that the best way to implement a POP3 and SMTP functions would be to use POCO. Unfortunately, cMake is giving me trouble. The version that came with CLion is 3.2 but the version that my machine is running is 2.8.
~$ cmake --version
cmake version 2.8.12.2
First problem. I thought that I could bypass this by just installing POCO and doing the same thing that I used for openssl which I also had to download.
cMakeList.txt:
cmake_minimum_required(VERSION 3.0)
project(Email_Reader)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
#included paths for openssl and POCO.
INCLUDE_DIRECTORIES("/usr/include/openssl")
INCLUDE_DIRECTORIES("/usr/local/include/Poco/Net")
set(SOURCE_FILES main.cpp)
add_executable(Email_Reader ${SOURCE_FILES})
The documentation for POCO tells me that I need at least 3.0 to work but I feel I have 2 different cMakes on my machine. Can you help me, please?
You can get the latest CMake release from: http://www.cmake.org/download/
For Linux, it's this archive: http://www.cmake.org/files/v3.2/cmake-3.2.2.tar.gz
An easy way to use it is to put the extracted files in /opt/cmake/cmake-3.2 then create the following aliases (e.g. in ~/.bash_aliases:
alias ccmake3='/opt/cmake/cmake-3.2/bin/ccmake'
alias cmake3='/opt/cmake/cmake-3.2/bin/cmake'
alias cmake3-gui='/opt/cmake/cmake-3.2/bin/cmake-gui'
alias cpack3='/opt/cmake/cmake-3.2/bin/cpack'
alias ctest3='/opt/cmake/cmake-3.2/bin/ctest'
Then, make sure that you have properly built and installed POCO.
The Getting Started page has all the information you need for doing that. But, basically, you should get the sources from here and extract them somehwere:
wget http://pocoproject.org/releases/poco-1.6.0/poco-1.6.0.tar.gz
tar xvfz poco-1.6.0.tar.gz
cd poco-1.6.0
mkdir -p cmake_build cmake_install/debug cmake_install/release
cd cmake_build
cmake3-gui ..
In the CMake 3 GUI, press Configure. In the new window, keep the default option Unix Makefiles and click on Finish. An error message should appear (which is fine), click Ok.
To build the Debug version, set the following:
CMAKE_BUILD_TYPE : Debug
CMAKE_INSTALL_PREFIX : the absolute path to "cmake_install/debug"
To get you started quickly with POCO, unckeck all the options, except for the following, they have to be enabled:
ENABLE_JSON
ENABLE_NET
ENABLE_UTIL
ENABLE_XML
POCO_STATIC
(You can consider the other options later if you need to...)
Quit the GUI, then build/install POCO:
make clean
make -j8
make install
Now, POCO should be installed in cmake_install/debug. To build/install the other versions, just do the same procedure, but replace Debug in CMAKE_BUILD_TYPE with Release, RelWithDebInfo or MinSizeRel (cf. CMake's doc) (also, you'll have to change the install directories)
Finally, you can use POCO in you C++ projects.
For instance, your CMakeLists.txt should look like this:
cmake_minimum_required(VERSION 3.0)
project(Email_Reader)
# define the project
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
set(SOURCE_FILES main.cpp)
add_executable(Email_Reader ${SOURCE_FILES})
# set the POCO paths and libs
set(POCO_PREFIX "/path/to/cmake_install/debug") # the directory containing "include" and "lib"
set(POCO_INCLUDE_DIR "${POCO_PREFIX}/include")
set(POCO_LIB_DIR "${POCO_PREFIX}/lib")
set(POCO_LIBS "${POCO_LIB_DIR}/libPocoNetd.a"
"${POCO_LIB_DIR}/libPocoUtild.a"
"${POCO_LIB_DIR}/libPocoJSONd.a"
"${POCO_LIB_DIR}/libPocoXMLd.a"
"${POCO_LIB_DIR}/libPocoFoundationd.a"
"pthread")
# set the include path for the app
target_include_directories(Email_Reader PRIVATE "${POCO_INCLUDE_DIR}")
# link the app against POCO
target_link_libraries(Email_Reader "${POCO_LIBS}")
My CMakeLists.txt for using Poco looks like this:
cmake_minimum_required(VERSION 3.10.0)
project(MyProject VERSION 0.1.0)
find_package(Poco REQUIRED COMPONENTS Foundation Net Zip )
add_executable(my_exe main.cpp)
target_link_libraries(my_exe PUBLIC Poco::Foundation Poco::Zip Poco::Net)
This configuration automatically add the needed include directories and libraries.
The Foundation component is mandatory, it seems it provides the include directories.
Don't add Poco to target_link_libraries, the linker will then look for a 'Poco' library.