Xmake
If you are bored of CMake and writing CMakeLists.txt, this is a better alternative.
Xmake is a powerful tool to manage build, execution, dependency management, and mix languages toghether. The biggest advantage for PRG1 is its watch mode and how easy it it to add GoogleTest. It has intuitive commands to execute and create a new project. Here are the basics you should understand to use it in PRG1.
Installation: See this page. On Fedora the Ansible playbook installs it via DNF.
Basics
Xmake uses xmake.lua as a configuration file, that's the equivalent of CMakeLists.txt for CMake. The most noticable difference is that is written in Lua. If you don't know Lua that's fine, I don't know it either and I managed to make it work.
How to create a new C++ project ?
Just xmake create will create a new folder with the same name as the current one, if you prefer to give it a name directly, use --project=<name>
temp> xmake create --project=super-project
create super-project ...
[+]: src/main.cpp
[+]: xmake.lua
[+]: .gitignore
create ok!
temp> cd super-project/
super-project> tree -a
.
├── .gitignore
├── src
│ └── main.cpp
└── xmake.lua
The file xmake.lua contains this
add_rules("mode.debug", "mode.release")
target("super-project")
set_kind("binary")
add_files("src/*.cpp")
It will generate a target (an executable binary) named super-project including all CPP files in the src folder.
Basic commands
xmakeis an alias ofxmake buildorxmake b, this is the first command to runxmake runorxmake rlet you run all targets,xmake run testswill run the target namedteststo avoid running all of themxmake cleanif you need to clean build files
Watch mode 🔥🔥
There is a xmake watch command, with a quiet mode (-q) and a way to give commands -c to run, separated by ;, this make is very easy to build + clear console + run the program like this:
xmake watch -q -c 'xmake; clear; xmake run'
Note: on Windows, clear is cls...
Recommended shell aliases
alias x "xmake"
alias xr "xmake run"
alias xbr "xmake && xmake run"
alias xw "xmake watch -q -c 'xmake; clear; xmake run'"
TODO: improve that
IDE integration
I guess there is a plugin for CLion and VSCode.
- TODO document this later
Formatting code
You can just format your code with Clang format by calling: xmake format
How to write tests with GoogleTest ??
GoogleTest (gtest) is a library very useful to write C++ tests. We could install it globally but that's easier to let Xmake download it from xmake-repo (a Github repository containing definitions of "packages", with one package named gtest)
- To ask Xmake to download this package:
add_requires("gtest")at the top - To include it during build:
add_packages("gtest")on the target - Include all files tests files and source files except the
main.cpp - Include the default
main()implementation fromgtestto avoid writing it yourself
Copy paste this content in your xmake.lua
add_rules("mode.debug", "mode.release")
add_requires("gtest")
target("super-project") -- your existing target
set_kind("binary")
add_files("src/*.cpp")
target("tests") -- build a `tests` target with all `.cpp` files inside `tests` folder
add_files("tests/*.cpp") -- include all tests files
add_files("src/*.cpp|src/main.cpp") -- add source files are they are included by tests files, but ignore src/main.cpp
add_packages("gtest") -- link the package we installed above
add_links("gtest_main") -- use the main() function written by the gtest library
- Note 1: if you have another structure that's fine too, adapt the
add_filesandremove_filescalls - Note 2: tabs are esthetic and entirely optionnal, if your formatter removes them it will also works.
Setup a first function to test, we'll create src/super-math.h and src/super-math.cpp to write some math functions there.
super-math.h
#ifndef SUPER_MATH_H
#define SUPER_MATH_H
int double_me(int a);
#endif
super-math.cpp
#include "super-math.h"
int double_me(int a) {
return a * 2;
}
Then we can setup the tests/tests.cpp (call it like you want, you might want several testing files later)
#include "../src/super-math.h"
#include <gtest/gtest.h>
TEST(DoubleMeSuite, DoubleMePositiveValues) {
EXPECT_EQ(double_me(23), 46);
}
We can now build and run this tests target
> xmake && xmake run tests
[ 30%]: cache compiling.debug tests/tests.cpp
[ 40%]: cache compiling.debug src/super-math.cpp
[ 50%]: cache compiling.debug src/super-math.cpp
[ 60%]: cache compiling.debug src/main.cpp
[ 70%]: linking.debug super-project
[ 80%]: linking.debug tests
[100%]: build ok, spent 0.238s
Running main() from /builddir/build/BUILD/gtest-1.14.0-build/googletest-1.14.0/googletest/src/gtest_main.cc
[==========] Running 1 test from 1 test suite.
[----------] Global test environment set-up.
[----------] 1 test from DoubleMeSuite
[ RUN ] DoubleMeSuite.DoubleMePositiveValues
[ OK ] DoubleMeSuite.DoubleMePositiveValues (0 ms)
[----------] 1 test from DoubleMeSuite (0 ms total)
[----------] Global test environment tear-down
[==========] 1 test from 1 test suite ran. (0 ms total)
[ PASSED ] 1 test.
As you can see the test is passing !
See section Writing automated tests with GoogleTest if you need an introduction.