I am using Google Protobuf with CMake. On Linux the Protobuf library is found by:
find_package( Protobuf REQUIRED )
CMake knows where to look for the library. How though do I get this to work in Windows? Is there an environment variable I should create, such as PROTOBUF_LIB? I have looked in FindProtobuf.cmake but cannot work out what is required.
I also struggled with this. To be more clear.
On Windows (7, similar on older windows):
Start → Control Panel → System → Advanced System Settings → Environment Variables
Then either on the top panel or the bottom panel (if you want it to apply to other users do it on the bottom), create two new variables. The 1st one is
CMAKE_INCLUDE_PATH which points at the bottom of your include path (should contain a "google" folder)
CMAKE_LIBRARY_PATH which should contain "libprotobuf" "libprotobuf-lite" "liteprotoc" .lib files.
After you create the variables press OK and then re-start cmake (or clean the cache).
Newest protobuf v3 have CMake support out of the box.
You could use protobuf repository as submodule and just use
add_subdiretory("third-party/protobuf/cmake")
to get all protobuf targets.
Then you can add dependency to protobuf with
target_link_libraries(YourLibrary libprotobuf libprotobuf-lite libprotoc)
Another possible way is available. With protobuf's CMake configuration you can build and install protobuf binaries once and use them across several projects in your development:
git clone https://github.com/google/protobuf.git
mkdir protobuf\tmp
cd protobuf\tmp
cmake ..\cmake
cmake --build .
cmake --build . --target install
Then you can use find_package with hint paths like
find_package(protobuf REQUIRED
HINTS
"C:/Program Files/protobuf"
"C:/Program Files (x86)/protobuf")
if (NOT PROTOBUF_FOUND)
message("protobuf not found")
return()
endif()
Hope this helps.
Protobuf on windows calls find_library which will search your PATH and LIB variables.
I found the way to use protobuf v2 with cmake on Windows and build it with your project settings. Please, try look to cmake-external-packages project and protobuf-v2 CMakeLists which do the job.
In fact, I wrote it because ExternalProject_Add is wrong (because does stuff in build phase instead of generation phase).
This CMakeLists.txt will download protobuf from protobuf's github releases, extract, and emit cmake targets which you should add reference to with target_link_libraries.
Use git-subtree, git-submodule or just copy this repository contents to your repository subfolder.
Then add packages you want to use with add_subdiretory. For protobuf, use:
add_subdirectory(path/to/cmake-external-packages/protobuf-v2)
Protobuf's includes will be copied to path/to/cmake-external-packages/include folder. You can customize its location in your top-level CMakeLists:
set (EXTERNAL_PACKAGES_INCLUDE_DIR ${CMAKE_CURRENT_LIST_DIR}/third-party/include
CACHE STRING "Directory for third-party include files, where include folders will be copied")
include_directories(${EXTERNAL_PACKAGES_INCLUDE_DIR})
Just reference protobuf for your executable:
add_executable(your_exe ${your_exe_sources})
target_link_libraries(your_exe libprotobuf libprotobuf-lite libprotoc)
Hope this helps.
Related
I am using Eigen3 with spectra (https://spectralib.org/), a library built on top of Eigen. Spectra uses find_package to find Eigen, and comes up with the error:
Could not find a package configuration file provided by "Eigen3" with any
of the following names:
Eigen3Config.cmake
eigen3-config.cmake
Looking through the directory of Eigen, I found that there were no files by those names, but rather one called Eigen3Config.cmake.in. I tried copying the file and renaming it Eigen3Config.cmake, but that gave me a different error of
find_package Error reading CMake code from "C:/Program Files
(x86)/Eigen3/cmake/Eigen3Config.cmake".
which was somewhat expected, but it does tell me that it can at least find the directory where Eigen3Config.cmake.in is. I'm assuming that either find_package is supposed to use Eigen3Config.cmake.in, or Eigen3Config.cmake.in is supposed to generate Eigen3Config.cmake, but i'm very new to cmake, so i'm not sure. How do I fix this?
There is no need to build/install Eigen to use it if you include it manually, as done in the getting started example (https://eigen.tuxfamily.org/dox/GettingStarted.html#title0)
But in order to be found by CMake, you will need to build / install it, as explained in the INSTALL file. https://gitlab.com/libeigen/eigen/-/blob/master/INSTALL
Usually, your error is followed by an hint asking you to set the variable Eigen3_DIR (or something similar) to point the build/install dir of the target project (Eigen3 here). It appears typically when you have built but not installed the project.
So:
Build Eigen
Install it (optional)
For spectra set the cmake var Eigen3_DIR to /path/to/Eigen/build . (if eigen not install or still not found)
These steps worked for me:
Install Eigen
Create a build directory for Eigen
cd into the build directory created
run "cmake ../"Your Eigen Source Directory""
After this is done, in your CMakeLists.txt of your project, you'll want to add "find_package( Eigen3 REQUIRED)" and "include_directories( ${EIGEN3_INCLUDE_DIR})".
I am trying to use the assimp library in a cross platform C++ project. I include the repo as a git submodule, so, effectively, if someone downloads my project they will also download the ASSIMP project.
After I go through the assimp build / CMAKE instructions and (on Linux) type make install and from then on in my project I can use:
target_link_libraries(${PROJECT_NAME} assimp)
However, there is no make install on Windows.
The only other way I have been able to include the library on Linux is to put (in my CmakeLists.txt file):
target_link_libraries(${PROJECT_NAME} ${CMAKE_SOURCE_DIR}/build/assimp/code/libassimp.so)
This is not cross platform as it hardcodes the name and location of the .so file which will not work on Windows.
How can I expose the library so that I can do something like target_link_libraries(${PROJECT_NAME} assimp) on all platforms?
My directory tree looks like:
- src
- include
- assimp
- bin
Where the assimp directory in the include directory is the git submodule
I think you're going about this the wrong way. You don't need to build assimp in a separate step from your project, and you don't need to make install to make it available.
There are a number of ways of handling third party dependencies in Cmake, since you've already chosen to submodule the assimp repository, we'll start there. Assuming assimp is located in the root of your repository in a directory called assimp/ this would be a barebones project including it:
cmake_minimum_required(VERSION 3.0)
project(Project myassimpproj)
# include your directories
include_directories(
${CMAKE_CURRENT_SOURCE_DIR}
)
# set any variables you might need to set for your app and assimp
set(BUILD_ASSIMP_TOOLS ON)
set(ASSIMP_BUILD_STATIC_LIB ON)
# add assimp source dir as a subdirectory, effectively making
# assimp's CMakeLists.txt part of your build
add_subdirectory(/path/to/assimp ${CMAKE_BINARY_DIR}/assimp)
add_executable(assimp_target main.cpp)
# be sure to link in assimp, use platform-agnostic syntax for the linker
target_link_libraries(assimp_target assimp)
There may be a better way of phrasing this using generator expressions syntax, but I haven't looked at assimp's CMakeLists.txt to know if it's supported (and this is a more generic way anyway.)
Not every project uses Cmake, so you may not be able to just add_subdirectory(). In those cases, you can effectively "fake" a user call to build them using their build commands on respective platforms. execute_process() runs a command at configure time add_custom_command() and add_custom_target() run commands at build time. You then create a fake target to make integration and cross your fingers they support Cmake someday.
You can also use the ExternalProject commands added to Cmake to create a custom target to drive download, update/patch, configure, build, install and test steps of an external project, but note that this solution and the next download the dependency rather than using the submodule'd source code.
Finally, I prefer to work with prebuilt dependencies, cuts down on build time, and they can be unit tested on their own outside of the project. Conan is an open source, decentralized and multi-platform package manager with very good support for C++ and almost transparent support for Cmake when used the right way. They have grown very stable in the last year. More information on how to use Conan with Cmake can be found here.
I created a new layer over an existing Yocto git for my company project.
In this layer I added a few external autotools based libraries.
A few applications need to link against this libraries and the application projects are all cmake based.
Taking one of this libraries (e.g. libcoap) I could easily find some FindCoAP.cmake to add to my library recipe.
Now if I was running on PC, it would simply be a matter of placing this FindCoAP.cmake file in cmake's ${CMAKE_ROOT}/Modules dir, but how should I, from inside a bitbake recipe (do_install hook), proceed to make my Find*.cmake modules available to anyone's dependent projects?
Should I try to get Yocto's cmake CMAKE_ROOT variable from system-information like this or is it a safer and more reliable way?
do_install_append() {
cmake --system-information | grep CMAKE_ROOT | cut -d \" -f2
install -d ${D}/$CMAKE_ROOT}/Modules
install ${S}/FindCoAP.cmake ${D}/$CMAKE_ROOT}/Modules
}
Thanks in advance.
To ship FindFoo.cmake with non-yet-cmake project
The ideal way is to update upstream project itself. So you will update your recipe and package FindFoo.cmake appropriately.
If you want to do it right now:
Add FindFoo.cmake to your layer (into the files directory next to your recipe).
Add that cmake file to SRC_URI (i.e. SRC_URI += "file://FindFoo.cmake").
Install it in do_install into the directory ${D}${datadir}/cmake/Modules/ for example.
Package it to the dev package by FILES_${PN}-dev variable (see example recipes below).
To use that cmake by other recipe
The usual way is to package .cmake files into the ${PN}-dev package. In your case, your application (which depends on the libcoap) will just set DEPENDS = "libcoap" and all the needed files (like headers, libraries and cmake file) will be copied (well, hardlinked) to the sysroot of your application.
CMake modules are packaged in various recipes for example:
libeigen
opencv
json-spirit
Your application is cmake based, so you will use inherit cmake in the recipe. Native module search path is set in cmake.bbclass.
(BTW, I do a build test of libcoap recipe from homeassistant layer and it worked, but obviously there is no cmake shipped.)
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
I'm working on the cmake scripts for my project and I've run into a problem:
My project uses a 3rd party library (FreeImage), which has its own Makefile-based build system. I can build FreeImage just fine by simply running "make" (I'm using gnuwin32), which will build FreeImage using MinGW and produce:
FreeImage.lib
FreeImage.dll
Now my problem is twofold:
I want to execute "make" from my cmake script.
I want to link to the import lib (FreeImage.lib), and also make sure the DLL gets copied to the correct place so the EXE will run.
I know how to link to the LIB file, but I'm lost on the rest.
The folder structure is like this:
MyProject # main directory
MyProject/Libs/FreeImage # FreeImage root directory
MyProject/Libs/FreeImage/Dist # This is where FreeImage outputs go (LIB and DLL)
BTW: I'm running on Windows 7. I plan to build my project both with MSVC and MinGW.
Thanks!
EDIT:
I'm now trying to use ExternalProject_Add like so:
ExternalProject_Add(
FreeImage
PREFIX ./Libs/FreeImage
URL ./Libs/FreeImage
BUILD_COMMAND make
)
This gets me part of the way there, but doesn't totally work... it tries to configure things for me and tries to use nmake... ugh
In my opinion, there are two options:
In case you have put your FreeImage sources in your projects' source-tree, the easiest option may be to use the execute_process() command. Assuming FreeImage is in your projects' source-tree in "3rdparty/FreeImage/" you can do something like,
execute_process( COMMAND make WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/3rdParty/FreeImage )
Optionally, you can copy the dll from 3rdParty/FreeImage/bin into you own bin directory. And then you can write a FreeImageConfig.cmake for importing the library:
add_library( FreeImage IMPORTED )
set_target_properties( FreeImage PROPERTIES IMPORTED_LOCATION ${PROJECT_SOURCE_DIR}/3rdParty/FreeImage/lib )
...
The other option is to make use of the ExternalProject module. You can also take a look at this article from Kitware for an overview of this module. In essence, you specify the full chain of commands needed to get the source, configure the build, build the source and install it. All in your own CMakeLists.txt