How to improve my script and copy program resources on build? - c++

So I got into a problem where I needed to use linux for a while instead of windows, and figured linux doesn't have Visual Studio. I then also realized that I made my project Visual Studio only, which I don't want.
So I looked up some CMake tutorials and try'ed creating some examples that could be loaded in both Visual Studio and CodeBlocks. When I got that to work, I went and code a CMake script for my actual program by piecing together what I learned and what I found in tutorials.
See here:
cmake_minimum_required(VERSION 2.8.9)
add_subdirectory(libraries/glfw)
project (OpenGLEngine3D)
include_directories(libraries/glfw/include)
include_directories(libraries/glm)
include_directories(libraries/glad/include)
include_directories(libraries/whereami/src)
include_directories(libraries/stb)
file(GLOB SOURCES "src/*.cpp" "src/*.h" "libraries/whereami/src/whereami.c" "libraries/glad/src/glad.c")
add_executable(OpenGLEngine3D ${SOURCES})
target_link_libraries(OpenGLEngine3D glfw)
Its dirty(I think) but it works.
So now my first question is, how to improve my CMake script? What is redundant or done in a poor way?
Now my program also requires some resources(like shaders, textures) which I have stored in a directory along with my CMake script, libraries and c++ files.
So my second question is, how would I tell CMake to the ide/compiler to copy the files in a certain directory to the program build directory(where the compiled binaries are) after compiling?(And have it only do it when the files aren't there ofc.)
Thanks!

I recently came across this article, which might be help you with CMake.
Here are a couple suggestions from me:
You're safe to use newer version of CMake. Currently, it's 3.11. There's no point in sticking to old versions.
Consider listing all your sources in a variable (using set command) instead of using file(GLOB). file(GLOB) will be evaluated only once, when generating build files. If you add new sources, you'll have to re-generate it manually, so it doesn't help too much, and is harder to debug (and really, debugging more complex CMake projects can be painful).
Avoid using include_directories (and link_libraries). Prefer using target_include_directories which works per-target. It allows to express dependencies between targets (when you have more than one - which might happen as your project grows)
You might consider using find_package(GLFW), instead of including GLFW in your project. Edit: actually, CMake doesn't came with find module for GLFW, but you can use an external module for this (e. g. this one) as described here.
Edit:
Example below illustrates the idea behind point 2), assuming that sources are placed in "src/" directory on the same level as CMakeLists.txt file:
set(engine_sources
"src/header_1.hpp"
"src/source_1.cpp"
# and so on for reset of files...
)
add_executable(OpenGLEngine3D ${engine_sources})
As for the second question: that's what file(COPY) command is for. Alternatively, you could just leave assets in source directory, and set working directory in IDE.
Side note: if you choose the second options, there appears to be a way to set this from CMake for Visual Studio, by setting VS_DEBUGGER_WORKING_DIRECTORY property:
set_target_properties(OpenGLEngine3D PROPERTIES VS_DEBUGGER_WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
(I haven't checked if this works as expected, as I rarely use VS. I remember looking for something like that in the past, and just recently came across it.)

Related

Cmake: find_library doesn't work but find_path does (same path)

I am trying to build a cross platform school project in C++ with CMake. My project requires the use of the Irrlicht library and must compile under Linux and Windows 10.
The project source path contains a lib folder, containing the Irrlicht header (in an include subfolder), an Irrlicht.dll, an Irrlicht.lib and a FindIrrlicht.cmake module.
I set CMAKE_MODULE_PATH to point to this directory, then call find_package(Irrlicht REQUIRED) in my CMakeLists.txt.
When I try to compile under Linux, everything works fine. However, when I try to run the configuration with CMake (using the CMake GUI) under Windows, the FindIrrlicht.cmake module that I have does not work (it should, since it is provided by the school and they say it should, also I know other people had it work without modifications). I believe that I have identified the cause of the problem, but I do not understance why it occurs nor how to fix it.
FindIrrlicht.cmake looks for the include directory and the Irrlicht.lib (or libIrrlicht.so under Linux, using prefix/suffix options) in some standard Linux include/library path AND under CMAKE_MODULE_PATH. When compiling on Windows, it should find everything in CMAKE_MODULE_PATH.
It calls find_library like this:
FIND_LIBRARY(Irrlicht_LIBRARIES
NAMES
Irrlicht
PATHS
"/usr/lib64/"
"/usr/lib/"
"/usr/lib/x86_64-linux-gnu/"
"/usr/local/lib/"
"/usr/local/lib64/"
"${CMAKE_MODULE_PATH}/" #Should find in this path for Windows configuration
"${Irrlicht_DIR}/"
)
The problem is, the path in CMAKE_MODULE_PATH is correct, since find_path() (see below) is able to find the include directory for Irrlicht. But it sets the Irrlicht_LIBRARIES as NOTFOUND. I verified times and again that the files are there and that the files are in the right place. I also checked the permissions on the files.
IF (NOT Irrlicht_INCLUDE_DIRS OR NOT Irrlicht_LIBRARIES)
FIND_PATH(Irrlicht_INCLUDE_DIRS
NAMES
irrlicht.h
PATHS
"/usr/include/irrlicht/"
"/usr/local/include/irrlicht/"
"${CMAKE_MODULE_PATH}/include/" #Does find in Windows
"${Irrlicht_DIR}/include/"
)
Also, later in the CMakeLists.txt I call a file(COPY "${CMAKE_MODULE_PATH}/Irrlicht.dll" DESTINATION ${EXECUTABLE_OUTPUT_PATH}) successfully, and tried it too with Irrlicht.lib with success. So the path is definitely not the problem here.
Thank you in advance for any help !
P.S.: This is my first time asking a question on StackOverflow, if I did/wrote something not right please let me know, I would be grateful.
Well, I found my problem. I feel stupid for not thinking about this sooner...
The problem was in the pre/suffixes, with some debugging output I realised that they were set for Linux instead of Windows, hence not founding the library file.
The reason for that is that in the CMakeLists.txt, the call to find_package was done before the call to project(), thus the MSVC variables was not set during the call to find_package, which led the script to believe it was called under Linux.

CMake cache windows

When using CMake on unix I dont have any issues. I can use CLion to do a cmake setup, cmake build and cmake install, open a different project and it will find the previously built library when using find_package. On windows this does not seem to be possible. By default it tries to install the build code into strange directories (like C:\Program Files). I have added a CMAKE_INSTALL_PREFIX to both my library CMakeLists.txt and the appliation CMakeLists.txt, however when using find_package(SDL2)CMake still complains there is no config file for CMake and SDL2. When checking the following file exists:
U:\various\cmake-cache\Program Files (x86)\SDL2\cmake\SDL2Config.cmake
The directory U:\various\cmake-cache was used as CMAKE_INSTALL_PREFIX for both SDL2 and my application. Yet it still refuses to compile.
What can I do to make CMake at least somewhat useful on windows? On Unix things work great, but it feels like a huge PITA on Windows so far... It seems like all the concepts dont work there. I would really like to have one central location that is used by every CMake build on my system and everything is installed there and when another project uses a library it is searched there. Is this possible?

Using CMake to find dependencies in an application-specific subfolder

In spite of many years of coding large-scale C++ applications, I do not understand how find_package is supposed to work in a medium-size CMake project, ASSUMING that I want to build the source to dependent packages myself and not simply rely on large systems like opencv, pcl or boost being installed somewhere in a system folder. I can't can't believe that I'm the only person in the world who has shipped multiple OpenCV and other open-source apps, has worked with meta-build systems like NAnt and SCons on major game projects, yet can't understand the most basic things about how CMake works or find a tutorial answering these questions.
In the past, I have essentially hacked around not understaning find_package by setting all the foo_DIR values by hand as CMake complains until I get a working folder.
I would like to run through a simple example which I'm working on right now, and dearly hope someone can explain what I'm doing so wrong.
Firstly, some assumptions:
I want to build everything for both MacOS and Windows, ideally via CMakeGUI. MacOS should build XCodeProjects and Windows should build Visual Studio Solutions.
Where there are dependencies, I want to compile them myself, so I have debug symbols and can modify the dependency source (or at least debug into it.)
No installation of pre-built binaries into system folders, i.e. no use of sudo port install opencv/pcl, etc on mac.
I have multiple projects, and prefer to keep a project and its dependencies in a single folder.
For the purposes of a concrete example, suppose I am building this project, although it's an arbitrary choice to illustrate the process and confusion I suffer:
https://github.com/krips89/opendetection
This lists dependencies, which I have intentionally reordered here so that I can take them in order, as follows:
find_package(OpenCV REQUIRED)
find_package(Eigen REQUIRED)
find_package(Boost 1.40 COMPONENTS program_options REQUIRED )
find_package(PCL REQUIRED)
find_package(VTK REQUIRED)
I would like to have all of these dependencies downloaded and configured in a single path (let's say c:\src on Windows, and ~\src on Mac for simplicity), NOT in a system path. Assume that the actual folder is a sub-folder for this project, and no a sub-folder for all projects. This should also allow for side-by-side installation of multiple projects on the same computer.
Taking this one step at a time:
(1) I clone openCV from https://github.com/opencv/opencv, sync to tag 3.1, configure into the folder opencv_build folder, build and install into opencv_install. I've done this so many times it's pretty straightforward.
(2) As above, but for eigen (although building for eigen doesn't actually do anything s it's a template library. I install to a folder eigen_install
Taking directory shows a series of folders for downloaded dependencies. I have assumed a convention where , and are source repos, and their following _build folders are the "WHere to build the binaries" folders in CMakeGui.
$ ls
boost_1_40_0 opencv opendetection_build
eigen opencv-build opendetection_data
eigen_build opencv_contrib pcl
eigen_install opendetection
All good so far, now let's try to configure opendetection and generate a solution into opendetection_build, and find pendetection's dependencies from within the ~/src folder, that is for the first two dependencies, I hope to find opencv and eigen in the opencv-build and eigen-build folders.
OpenCV immediately fails, as expected, saying:
Could not find a package configuration file provided by "OpenCV" with any of the following names:
OpenCVConfig.cmake
opencv-config.cmake
Add the installation prefix of "OpenCV" to CMAKE_PREFIX_PATH or set "OpenCV_DIR" to a directory containing one of the above files. If "OpenCV" provides a separate development package or SDK, be sure it has been installed.
That's good, because I want to explicitly tell CMake to look for dependent packages under my ~/src folder. Question: Is the use of CMAKE_PREFIX_PATH=/users/foo/src the recommended way to accomplish what I want - looking for all sub-packages under a specific path?
Following this, CMake finds OpenCV (good), and sets OpenCV_DIR = /Users/foo/src/opencv-build.
Question: Given that I have made an "install" to opencv-install (using CMAKE_INSTALL_PREFIX and building the Install Target Of OpenCV, shouldn't it find OpenCV in the opencv-install folder not opencv-build?
Moving on to eigen, I have configured and built eigen, and installed it to ~/src/eigen-install, which since it is a subfolder of CMAKE_PREFIX_PATH (~/src) I might expect to be found. But it doesn't seem to be. Can somebody explain to me what I'm not understanding? Particularly given that Eigen in a template library, and that there are at least three folders (eigen, eigen_build and eigen_install) under CMAKE_PREFIX_PATH which I would have thought CMake would find something in, I assume I must be doing something wrong here. I KNOW from past experience, I can set EIGEN_INCLUDE_DIR by hand in CMakeGUI by hand, and continue hacking forth, but that just seems wrong.
I'm more than willing to write up a web page explaining this for future people as dumb as me if one does not already exist, although I can't understand how use of CMake for basic project configuration and generation is apparently so obvious to everyone but so opaque for me. I have actually been using CMake for some years, usually by just manually setting Boost_INCLUDE_Dir, Foo_INCLUDE_PATH etc manually, but clearly this is not the right solution. Generally, after spending a couple of days fighting through the various packages to generate a solution by manually setting INCLUDE PATHS, LIBRARY PATHS and other options, I just deal with the solution and don't touch CMake again. But I would love to understand what I'm missing about find_package for my (surely not uncommon) use case of wanting to control my project dependencies rather than just using sudo port install * and installing random versions of projects to my global system folders.
As error message says, CMAKE_PREFIX_PATH should be set to installation prefix of the package. E.g., if the package has been built using CMake, this is CMAKE_INSTALL_PREFIX variable's value, if the package has been build using Autotools, this is value of --prefix option used for configure it, and so on.
CMake doesn't search every directory under CMAKE_PREFIX_PATH. That is why specifying it as /users/foo/src is useless if you have the package installed at /users/foo/src/eigen-install.
Instead, you may install all 3d-party packages into /users/foo/src/install, and use that path as CMAKE_PREFIX_PATH in your main project.

Using biicode and clion?

Is there an easy way to use clion (e.g. debugging) in a c++ project using biicode as construction tool?
In fact, both systems work with cmake, but biicode generates CMakeLists.txt that clion doesn't seem to understand (the one located in blocks/ nor the temporary one in cmake/).
Right now I could only work by using biicode self-generated CMakeLists.txt for regular builds, and a hand-crafted CMakeLists.txt to compile within clion. However duplicating the description of the construction does not sound like a good idea.
I guess some elaborated dark scripting could be done (I am pretty new to cmake), but I'm just playing around and I don't think it is worthwhile to do it or ask for it.
Has anyone tried to use clion and biicode? Is clion fully supporting cmake yet? Is biicode using internal code that fully cmake-compliant tools won't understand? Am I missing some silly idea?
Currently it is not possible. Unfortunately both biicode and CLion use cmake and use different conventions about the project layout/structure, and at the moment they are simply incompatible.
The good news are that the people at CLion are helping a lot to figure out the best solution so hopefully this will be fixed soon.
EDIT 19-Feb-2015: Now biicode 2.4.1 and last CLion EAP are compatible. You can open an existing biicode project in CLion using these steps:
CLion->Open project, navigate to your biicode project/cmake/ folder and open it (where the CMakeLists.txt lives)
CLion->Change project root, select your main biicode project folder.
Then you should be able to build and run your targets.
It can be convenient to check in Settings->Build, Execution, Deployment->CMake, "Automatically reload CMake on editing".
And remember, if you change your project, add or remove files, main executables, add or remove dependencies, to run $ bii cpp:configure so the whole project is updated
Now biicode and CLion work fully with each other. Here's a guide from biicode docs to use CLion.
Biicode has been replaced by Conan.io, which is far easier to use with CLion.

Making a cross platform library with CMake?

Is CMake difficult to use? I've been developing a library using Windows and MSVC++ . I tested my code in Linux and OSX by tediously making objects from each file and making a library out of this.
I have several Directories ex:
Agui
-> Widgets
->Button
->ListBox
-> Backends
-> Allegro
And what I'd like is, for example, if I'm on Windows, it auto generates an msvc project with all these directories and files included and ready to be compiled.
On Linux and OSX I'd like to be able to do something like
cmake
make
is this possible with CMake, and easy to do given my situation.
Thanks
Yes, that is exactly the reason CMake is made for. Huge projects like KDE use CMake.
And its easy to setup.
This is exactly what CMake was developed to do. CMake generates native build files and workspaces that can be used on your platform of choice. So on Unix this is normally Unix Makefiles, on Windows Visual Studio you can select your Visual Studio version to generate a solution that can be opened in the IDE, or use NMake Makefiles.
If you want to add a simple library, you just use the add_library function, giving it a library name and a list of source files. I would recommend taking a look at the CMake tutorial for a brief overview. There is also a book, Mastering CMake, along with many tutorial pages. You can ask the CMake command line for help too, 'cmake --help-command add_library' would show you the add_library documentation.
CMake will generate project files for a number of IDEs, but I find that automake+libtool tend to be easier to use. Here is an excellent tutorial: http://www.lrde.epita.fr/~adl/autotools.html
Don't be put off by the page count: most of it is step-by-step revealing of diagrams.