A better alternative to solution files

The Partridge Family were neither partridges nor a family. Discuss.
User avatar
cyboryxmen
Posts: 190
Joined: November 14th, 2014, 2:03 am

A better alternative to solution files

Post by cyboryxmen » August 6th, 2018, 12:46 pm

For years now, the community has been sharing their projects using solution files. While this has worked fine thus far, it gets annoying when someone using Visual Studio 2017 opens up a project from Visual Studio 2015 and the build tools are set up differently. Also, if someone using another program like CLion/CodeBlocks wants to look at your C++ project, they won't be able to open the solution file. Fortunately, Visual Studio has a new way of allowing you to build C++ projects without the use of a solution file: CMake.

CMake is a universal build system that allows you to create C++ projects that can be used by various programs. A large variety of programs use it to develop and build C++ projects including CodeBlocks, CLion, Eclipse, MinGW, Sublime Text and of course, Visual Studio. As a result, your C++ project can be used by any program other than Visual Studio by simply using CMake instead of a solution file. It'll also work across different Visual Studio versions so you no longer have to worry about opening solution files that are made in a different version of Visual Studio!

A CMake project is based around a CMakeLists.txt. With Visual Studio 2017, you can now open these CMakeLists.txt directly using their CMake plugin!

Image

Here is a simple example of a CMake project that you can try to open with this new plugin. It should be a good example of a standard CMake project while also being simple enough to show you all you need to know to use CMake. Let's take a look at the main CMakeLists.txt file in the root folder.

Code: Select all

cmake_minimum_required(VERSION 3.11)
project(first-cmake VERSION 1.0.0 DESCRIPTION "A test to see if I can make a CMake Project" LANGUAGES CXX)

# Build the math project.
add_subdirectory("${CMAKE_CURRENT_SOURCE_DIR}/math")
# Build the calculator project.
add_subdirectory("${CMAKE_CURRENT_SOURCE_DIR}/calculator")
# Build the parser project.
add_subdirectory("${CMAKE_CURRENT_SOURCE_DIR}/parser")
Notice the lines with '#' at the start. These lines specify comments just like how '//' specify comments in C++.

The first line specifies what version of CMake the file uses. The latest version is 3.12 but 3.11 is the latest one Visual Studio 2017's CMake plugin supports.

Each CMakelists.txt represents a CMake project. The next line defines what the project is. You can specify the project name, description, version and the languages the project uses. All of the CMake projects in this example is set to use The C++ language(CXX).

The next couple of lines will add additional CMake projects to the build. We do this by specifying the folder the additional CMakeLists.txt(s) are located in. This is what allows us to build multiple CMake projects using only one CMakeLists.txt. ${CMAKE_CURRENT_SOURCE_DIR} will give out the location of the current CMakeLists.txt. By using this instead of hard-coding a fixed location, we can shift the entire CMake project around anywhere we want and it'll still build!

Now let's look at the other CMake projects.

Code: Select all

cmake_minimum_required(VERSION 3.11)
project(math VERSION 1.0.0 DESCRIPTION "A basic header only math library" LANGUAGES CXX)

# The library is a header only library. It won't be compiled.
add_library(math INTERFACE)
# Declare that the library uses C++17.
target_compile_features(math INTERFACE cxx_std_17)
# Declare the library's includes.
target_include_directories(math INTERFACE "${CMAKE_CURRENT_SOURCE_DIR}/include")
# Declare the library's files.
target_sources(math INTERFACE "${CMAKE_CURRENT_SOURCE_DIR}/include/math/math.hpp")
This CMake project defines the math library "target". Targets are what CMake uses to represent libraries and executables. You can define multiple targets in one CMake project but it's considered good practice to only define only up to one target per project. This target is not only a library target but an INTERFACE target too. That means that it doesn't need to be "compiled" in any way. In our case, the math library is a header only library so it requires no compilation.

We just need to set its "properties" like the version of C++ it uses and the files used in the library. These properties define how the library target is going to be used by other targets. The math library is set to use C++17 and all of its include headers is located in the folder "${CMAKE_CURRENT_SOURCE_DIR}/include". The last line defines what files are part of the library. Right now, <math.hpp> is the only file in the math library. In Visual Studio, this line is important as it defines what files are given Intellisense for the math project. For non-INTERFACE targets, it also defines what to compile too. You might also notice the keyword INTERFACE is used when setting these properties. This is required for INTERFACE targets like the math library. I'll explain this keyword later in more detail when it becomes relevant.

Now onto the next CMake project.

Code: Select all

cmake_minimum_required(VERSION 3.11)
project(parser VERSION 1.0.0 DESCRIPTION "A simple parser library" LANGUAGES CXX)

# Declare the library.
add_library(parser)
# Declare that the library uses C++17
target_compile_features(parser PUBLIC cxx_std_17)
# Declare our includes.
target_include_directories(parser
	PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include"
	PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/internal")
# Declare the library's files.
target_sources(parser
	PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include/parser/parser.hpp"
	PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/source/parser.cpp"
	PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/internal/internal/internal.hpp"
	PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/source/internal.cpp")
Unlike the math project, the parser target is a library that needs compilation. You can see that we set the same properties that we set for the math project but this time, we use the keywords PUBLIC and PRIVATE. These keywords are only relevant when linking targets together. This is similar to how a library in Visual Studio is linked to other libraries or executables. You can see how linking in CMake works later.

Keywords like PUBLIC, PRIVATE and INTERFACE are scope specifiers. They set whether these properties "transfer" to other targets that link to it. PUBLIC means that the properties apply to the target and other targets that link to it. PRIVATE means that the property only applies to the target and targets that link to it are not affected by them. Finally, INTERFACE properties will not affect the target but will affect targets that link to it. You can take a look at how these properties are set to get a feel of which scope to use for which property depending on the situation.

Now let's take a look at our last CMake project.

Code: Select all

cmake_minimum_required(VERSION 3.11)
project(calculator VERSION 1.0.0 DESCRIPTION "A simple calculator application" LANGUAGES CXX)

# Declare the executable.
add_executable(calculator)
# This executable is compiled with C++17.
target_compile_features(calculator PRIVATE cxx_std_17)
# Declare the libraries this executable uses.
target_link_libraries(calculator PRIVATE math PRIVATE parser)
# Declare the executable's includes.
target_include_directories(calculator PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/include")
# Declare the executable's files.
target_sources(calculator
	PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/include/command-line-calculator.hpp"
	PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/source/command-line-calculator.cpp"
	PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/source/main.cpp")
This project defines an executable target. It has the same properties we've seen before but they are all set to PRIVATE. Scope specifiers are irrelevant when it comes to executables since executables can't be linked to anything. We need to specify them anyway since it is a target and all target properties in CMake have scope whether they are properties for executables or libraries. You can set the scope to anything you like but PRIVATE just makes the most sense.

Additionally, you can see how linking works in CMake here using the target_link_libraries() command. This command is what allows you to link targets like "math" and "parser" to the current target, "calculator". As you can see, we can link "math" and "parser" to "calculator" even though they are not specified anywhere in the file. This is where the beauty of CMake with targets shine. Remember when the first CMake project adds all of these projects into one build? By doing that, it'll add the targets they define to the build too allowing them to be linked later. The calculator project does not need to know about the other projects to use their targets. It doesn't need to know where they are located, what targets they define nor what properties those targets have. All it needs is this one line:

Code: Select all

target_link_libraries(calculator PRIVATE math PRIVATE parser)
With that, the calculator target is able to use those libraries without much fuss.

That's all you need to know to do everything you're already doing but better using CMake! I'm going to use CMake to build by C++ projects from now on. The portability of it is nice but I also find it easier to configure my projects with them than editing the project settings in Visual Studio. It's certainly makes it easier to manage multiple libraries in a project.

To read more about CMake, click here!
Last edited by cyboryxmen on August 23rd, 2018, 12:01 pm, edited 1 time in total.
Zekilk

User avatar
chili
Site Admin
Posts: 3948
Joined: December 31st, 2011, 4:53 pm
Location: Japan
Contact:

Re: A better alternative to solution files

Post by chili » August 6th, 2018, 11:45 pm

You can have my .sln files when you pry them from my cold dead hands!!

I really need to learn CMake tho... if for nothing else than at least for linux C++ dev.

One day...
Chili

User avatar
cyboryxmen
Posts: 190
Joined: November 14th, 2014, 2:03 am

Re: A better alternative to solution files

Post by cyboryxmen » August 23rd, 2018, 12:55 pm

I edited the post to better explain CMake. Hopefully, that'll clear up some misconceptions!
Zekilk

albinopapa
Posts: 4373
Joined: February 28th, 2013, 3:23 am
Location: Oklahoma, United States

Re: A better alternative to solution files

Post by albinopapa » August 23rd, 2018, 5:45 pm

While using a build solution to reach a wider audience is nice and efficient, I for one like the fact VS handles all the gathering and logging of files and compilation flags instead of having to list all that out manually. VS's cmake integration does make using and compiling cmake projects much simpler, but I've found that using something like the CMake Gui a necessity on occasion. Adding an extra step and extra software just to compile the project. I don't know if it is because the plugin was too old or not all tags were recognized, didn't care to dive too deep into how CMake worked.

I do wish there was a unified standard for code projects; I'm sure it'd have to be specific to each type of programming language. Visual Studio's way of using XML seems to be appropriate to store the compiler flags, compilation flags and file lists. I love automation and graphical interfaces, so not about to move to another build system or compiler where you have to list out each directory or file in your project to be compiled.
If you think paging some data from disk into RAM is slow, try paging it into a simian cerebrum over a pair of optical nerves. - gameprogrammingpatterns.com

PotatoWedgie
Posts: 6
Joined: June 12th, 2017, 10:33 pm

Re: A better alternative to solution files

Post by PotatoWedgie » September 19th, 2018, 9:33 pm

so is there a cmake version of the chiliframework then? i prefer linux and vscode but i'm a n00b-face

albinopapa
Posts: 4373
Joined: February 28th, 2013, 3:23 am
Location: Oklahoma, United States

Re: A better alternative to solution files

Post by albinopapa » September 20th, 2018, 12:36 am

PotatoWedgie wrote:so is there a cmake version of the chiliframework then? i prefer linux and vscode but i'm a n00b-face
No and it wouldn't make much sense anyway because the framework is built using Windows APIs like creating the window and the Direct3D API. Not that you couldn't modify it to create a Linux window and use OpenGL. Plus, chili's getting started and other compiler related videos cover Visual Studio 2015/2017 so wouldn't be relevant for the 'nix users.

Does VSCode support .sln files? Haven't tried it. If it does, you may be able to at least get the project open and switch over bits of code to support linux and opengl.
If you think paging some data from disk into RAM is slow, try paging it into a simian cerebrum over a pair of optical nerves. - gameprogrammingpatterns.com

PotatoWedgie
Posts: 6
Joined: June 12th, 2017, 10:33 pm

Re: A better alternative to solution files

Post by PotatoWedgie » September 20th, 2018, 12:01 pm

No, vscode uses workspaces and whatever build files you tell it to. I've been learning c++ / opengl from thebennybox but encountered a roadblock. I'm learning cmake now. I use the Unreal Engine primarily anyway, it's just that it's an enormous temperamental beast and I wanna play around with something more basic for educational purposes. I can always just confine my chilinanigins to my crappy Windows laptop I guess.. for now..

PotatoWedgie
Posts: 6
Joined: June 12th, 2017, 10:33 pm

Re: A better alternative to solution files

Post by PotatoWedgie » September 28th, 2018, 10:15 pm

i guess windows aint so bad....

albinopapa
Posts: 4373
Joined: February 28th, 2013, 3:23 am
Location: Oklahoma, United States

Re: A better alternative to solution files

Post by albinopapa » September 29th, 2018, 2:08 am

It's been awhile since I messed with Linux, but never took the time to learn all the shell script BS.

I like my GUI. I hated the days of DOS. I love VS for it's auto completion and intellisense, can't do much without it, it's become a crutch.
If you think paging some data from disk into RAM is slow, try paging it into a simian cerebrum over a pair of optical nerves. - gameprogrammingpatterns.com

PotatoWedgie
Posts: 6
Joined: June 12th, 2017, 10:33 pm

Re: A better alternative to solution files

Post by PotatoWedgie » September 29th, 2018, 5:59 pm

I use Linux Mint. Its GUI is just as good as windows and vscode is just as good as visual studio. I prefer Linux because it's more transparent. I find on Windows that even with an admin account, I still feel overly restricted. Also, Cinnamon is much prettier than Windows. I currently have it all red and it looks amazing. Tried that on Windows and it looks crap.
Plus, you can't beat copying and pasting a magic command into the terminal and it just sorts everything out for you. On Windows it's like a million clicks to do anything.

Post Reply