Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Help needed while setting up basic multiplatform cmake-enabled project

tl;dr the questions are at the bottom.

I am a developer trying something new - my last poison is c++. As I am spending half of my time on my linux laptop and the other half on Win XP PC, I tried to find a way to create basic, barebone project, using good c++ practices (well, I don't know them from experience, I just read about them). Right now my project almost works while using cmake . && make on linux (it works when header and source files are in the same folder, fails when I separate them to include / src folders). I am using nuwen's distribution of mingw on windows (and I know that the toolchain is working, it compiles projects from within Eclipse without any problems).

My project directory looks like this:

engine 
    |
    |- main
         |
         |- include
                 |
                 |- App.h  
                 |- CMakeLists.txt (2)
         |- src
             |
             |- main.cc
             |- App.cc
             |- CMakeLists.txt (3)

    |- CMakLists.txt (1)

The contents of the files are very simple (I will remove the include guards, etc for clarity)

App.h:

class App {
   public:
      App();
      int onExecute();
};

App.cc:

#include <iostream>
#include "App.h"

App::App() {
}

int App::onExecute() {
   std::cout << "inside app.." << '\n';
   return 0;
}

main.cc:

#include <iostream>
#include "App.h"

using namespace std;

int main(int argc, char* argv[]) {
  App a;

  a.onExecute();
  std::cout << "inside main.." << '\n';
}

CMakeLists.txt (1) - the main one:

cmake_minimum_required (VERSION 2.6)
set (CMAKE_CXX_COMPILER "g++")

project (gameengine)

add_definitions ( "-Wall -ansi -pedantic")

add_subdirectory (${CMAKE_SOURCE_DIR}/main/include)
add_subdirectory (${CMAKE_SOURCE_DIR}/main/src)

add_executable (engine ${CMAKE_SOURCE_DIR}/main/src/main.cc)
target_link_libraries (engine Application)

CMakeLists.txt (2) - inside the include directory

add_library (Application App)
set_target_properties (Application PROPERTIES LINKER_LANGUAGE CXX)

CMakeLists.txt (3) - inside the src directory

include_directories (../include)

And this is as far as I got - with some changes (i.e. moving App.cc to the include directory) the whole thing compiles and runs fine on linux - but I can't get the mingw generator to work on Win XP. I hand tuned the CMAKE_MAKE_PROGRAM in the file CMakeCache.txt to point to the proper make.exe (I know that this should be defined as a system variable but as I am working on many different PC's, I don't want to leave junk after me).

My questions are:

1) what are the guidelines for writing multiplatform CMakeLists.txt file (which will work independly of the os and the location of the project files), which preferably will allow me to easy swich my project configuration from one os the other one?

2) how can I address the error of not finding the header file (make gives: (...)\engine\main\src\main.cc:2:17: fatal error: App.h: No such file or directory) ?

Thank you for your time and help.

like image 690
zeroDivisible Avatar asked Nov 03 '10 07:11

zeroDivisible


1 Answers

1) what are the guidelines for writing multiplatform CMakeLists.txt file (which will work independly of the os and the location of the project files), which preferably will allow me to easy swich my project configuration from one os the other one?

Well, I'm certainly no expert, but I can share my 10-month experience with a cross-platform cmake-based project.

Right off the bat I think you really should be using out of source builds. This means that you don't run cmake in the same directory where your code is; instead, you create a new folder, e.g. engine/build and run cmake ../main from there. This way you don't clobber your source files with cmake stuff, such as CMakeCache.txt etc. There are even some macros you can use to forbid your users from doing in-source builds.

I also find it useful to create a set of macro files to help set compiler options for different platforms. Here at work we have macros such as ADD_GCC_FLAG or ADD_MSVC_FLAG which check the current compiler and add flags accordingly.

I think it is good practice to have a single .cmake file which concentrates all your project configurations in one place. At work all our CMakeLists.txt start with include( ../cmake/configs.cmake ). This file sets all sorts of options, such as standard include directories, default compiler flags etc.

To assuage your problem with include directories, I suggest you use absolute rather than relative paths in your source files. Define a standard include directory, for instance engine/main/include and always #include files relative to that path. In your example, if you wanted to include engine/main/include/somefolder/header.h, you'd write #include <somefolder/header.h> (using <> instead of quotes tells the C++ preprocessor to skip the current directory when looking for the file).


2) how can I address the error of not finding the header file (make gives: (...)\engine\main\src\main.cc:2:17: fatal error: App.h: No such file or directory) ?

There are a number of issues with your cmake layout, but the reason you were getting that error is because you need to call include_directories in CMakeLists.txt (1) as well.

Besides that, your other CMakeLists.txt files have problems too. In CMakeLists.txt (2), the arguments to add_library are wrong; it should be ../src/App.cc, otherwise you're just adding an empty library. And you don't need that set_target_properties either, at least not if you got the add_library arguments right. You also need a include_directory call in that same CMakeLists.txt that's adding the library; putting it in (3) doesn't really do anything.

Actually, you don't need a CMakeLists.txt file in the include directory, since there's nothing to build there. It's better to put the add_library call in CMakeLists.txt (3), right after calling include_directories.

I hope this clears some of your doubts.

like image 163
Pedro d'Aquino Avatar answered Oct 02 '22 23:10

Pedro d'Aquino