Cmake: Is this the right way to do it?

Started by
7 comments, last by mychii 7 years, 3 months ago

I'm still learning on using cmake and I don't really understand how I should work on it. I'm used to using Visual Studio and have it doing everything for me, so I'm trying to do it in a "Visual Studio" way... not sure if it's that's what it means though... cause when the cmake provided me a VS solution files, when I open it, each cpp becomes its own project... I'm kinda confused. But everything compiles okay... so I'm not sure if I'm doing it right.

I've made a simple project below using cmake and I wonder if this is the correct way to structure the files and folders using cmake.

~ the tree ~

- CMakeLists.txt

- main.cpp

- test/

---- CMakeLists.txt

---- component/

-------- CMakeLists.txt

-------- component.h

-------- component.cpp

---- core/

-------- CMakeLists.txt

-------- core.h

-------- core.cpp

---- interface/

-------- CMakeLists.txt

-------- interface.h

~ the files ~

CMakeLists.txt


cmake_minimum_required (VERSION 3.4.1)
project (Test)
add_subdirectory(test)
add_executable(Test main.cpp)
target_link_libraries(Test test_core)

main.cpp


#include <iostream>

using namespace std;

int main()
{
	cout << "Hello World" << endl;
	int x;
	cin >> x;
	
	return 0;
}

test/CMakeLists.txt


cmake_minimum_required(VERSION 3.4.1)

add_subdirectory(component)
add_subdirectory(core)

test/component/CMakeLists.txt


cmake_minimum_required(VERSION 3.4.1)

include_directories(../interface)
add_library(test_component component.cpp)

test/component/component.h


#ifndef COMPONENT_H
#define COMPONENT_H

#include "../interface/interface.h"

class Component : public Interface
{
public:
    Component();
    void getMessage();
    virtual ~Component();
};

#endif

test/component/component.cpp


#include "component.h"

Component::Component()
{

}

void Component::getMessage()
{

}

Component::~Component()
{

}

test/core/CMakeLists.txt


cmake_minimum_required(VERSION 3.4.1)

add_library(test_core core.cpp)
target_link_libraries(test_core test_component)

test/core/core.h


#ifndef CORE_H
#define CORE_H

#include <string>

#include "../component/component.h"

class Core
{
public:
    Core();
    virtual ~Core();
};

#endif

test/core/core.cpp


#include "core.h"

Core::Core()
{
    Component component = {};
}

Core::~Core()
{

}

test/interface/interface.h


#ifndef INTERFACE_H
#define INTERFACE_H

class Interface
{
public:
    virtual void getMessage() {}
};

#endif

Sorry for too much code.. I hope it's clear enough.

Advertisement

It looks fine to me.

Every add_executable() will add an executable project in your solution, and add_library() a static library.

If you add move files to a folder they will go into the proper project.

I would recommand adding the header files to the projects to make them visible in VS like this:

add_library(test_component component.cpp component.h)

Cheers

Glad to hear that, and thanks for the tip, it worked.

So let me get this straight... if I start using CMake, I have to focus not on making the code on VS and do it manually (which I have no idea what, text files?)? I mean, I opened the VS and it's almost kind of a mess (I'm not used with folders separated as libs instead of actual folder consisting .h and .cpp only), and in the end I started to think that the VS is only meant to only compile the code in this kind of environment. But if I look to my files, it's been bloated with tons of cmake generated files that I can hardly see my source codes:

6Tlaphs.png

I'm quite confused on how I should work with my project with this kind of environment. Like I said before, I'm used to work inside the VS, not with Cmake like this, so I need to be sure how.

I'm not sure what you mean by "If you add move files to a folder they will go into the proper project." Is my concern above is what you mean?

So, there are a couple comments for you:

1. In your CMake files you don't need to have the minimum version command in each file. You only need that in the top most file with the project command in it, so remove that from the other ones and it will make things a little cleaner.

2. You need to use what is known as an "out of source" build to prevent CMake from polluting your source folders. I suggest to start using the CMake GUI till you get the hang of it, here is an example from my personal codebase:

[sharedmedia=core:attachments:34163]
See how I have a separate folder to contain all the intermediate files (the "Where to build the binaries" field), that is where the SLN will be generated and all the CMakeFiles, Debug, Release and other directories will stay within that folder instead of spreading out all over your project. The other folder "Where is the source code" points to the folder with your top level CMakeLists.txt file.

3. For the project which has nothing but headers in it, you should use add_library(libName INTERFACE ${HEADERS}) such that there will be no 'build' rules but you can see the headers and they are included by other libraries as normal.

4. If you wish to clean your IDE up in general, look at the commands set_property (TARGET libName PROPERTY FOLDER LocationInIDE) and source_group (IDELocation FILES ${Files}) to tell the various IDE's where you want files to appear. For instance, again from my personal codebase:

[sharedmedia=core:attachments:34164]

As you can see, that has 104 projects in it. If I did not tell CMake to generate some organization data for IDE's it would be a nightmare to navigate. With the general layout organizing things, it is actually not too horrible to work with. This solution contains about 400 projects when I turn on full detail unit tests and everything else such as embedded 3rd party dependencies and other things, yet other than the build time sucking it is still navigable.

Now, as to the workflow. It is a bit different, though by no means are you completely out of luck when it comes to using the tools supplied by IDE's. Suppose you right click a folder and add a class, VS will create the files and add them to the projects. For the moment everything works just fine but if you regenerate using CMake those files will not be part of the build anymore. So, you can still use the new class and other tools in VS but you have to take the manual step of going into the CMakeList.txt for the appropriate library/exe and add the files there also. After that, the next time you build CMake will regenerate the projects and your files will still be there. Personally, I use Sublime Text to do all my CMake editing and file creation, there are some nice syntax highlighters etc. If I happen to be on OsX or Linux though, I use Clion as my IDE which has no solutions, it actually uses CMake internally so you add/remove files and it generally takes care of the CMakeLists for you behind the scenes, even with my heavily customized CMake setup it usually gets it correct.

Hope this all helps.

Wow this is going to be a lot of changes to grasp :wacko:, but all the answers I need so far. That project structure is surely clean :wub: .

Thanks a lot AllEightUp, especially the workflow part, that is gold. Welps, gotta catch up with the suggestions. Thanks again guys! :lol:

Other than the basic settings needed to just get everything built correctly, a lot of CMake configuration comes down to personal preference.

For instance, I noticed you had a test/CMakeLists.txt with no targets, and only add_subdirectory() commands. I personally don't like having those kinds of "glue" CMakeLists unless they're also creating targets. I also prefer to use the TARGET_* command variants that operate on targets, as opposed to those that operate on directories, just because I like the explicitness. But again, that's just me :)

You mean like what AllEightUp suggested at no 4? Yeah I've tried it and it looks great on the build result. However somehow it only works on VS but not Android Studio.

Anyway I'm using Clion now so I guess it's not an issue anymore, but it's no harm that I'm still adding that command nonetheless.

You mean like what AllEightUp suggested at no 4? Yeah I've tried it and it looks great on the build result. However somehow it only works on VS but not Android Studio.

Anyway I'm using Clion now so I guess it's not an issue anymore, but it's no harm that I'm still adding that command nonetheless.

You're referring to the SOURCE_GROUP command specifically. I was just commenting on the fact that you can get a CMake build up and working with a mere handful of commands (add_library(), add_executable(), etc.) to start, and from there layer in the extra configuration you need for your IDE, or to get everything properly installed and exported, etc.

So there's no reason you have to learn absolutely everything about CMake in one go; you can learn little by little while still taking advantage of it!

Cool, thanks for the attention Zipster. :-)

This topic is closed to new replies.

Advertisement