Skip to content

Instantly share code, notes, and snippets.

@stryku
Last active June 19, 2020 06:21
Show Gist options
  • Star 6 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save stryku/50903f147c899a84c20515a6bc5fab97 to your computer and use it in GitHub Desktop.
Save stryku/50903f147c899a84c20515a6bc5fab97 to your computer and use it in GitHub Desktop.
CMakeSL (CMake Scripting Language) - An attempt to introduce a new scripting language for CMake

CMakeSL (CMake Scripting Language) - An attempt to introduce a new scripting language for CMake

Agenda

  • Abstract
  • Video
  • Why
  • How
  • Current status
  • Future plans
  • How to
  • Discussion and links

Abstract

The purpose of this article is to showcase a project that I've recently been working on. The project itself is a set libraries implementing a completely new scripting language for CMake, as well as tools for IDEs creators (at least, that's the intent). I'm going to explain the why, the how, and the current status and then discuss the plans I have for it for the near future.

I'd like to come clean and say that the project is not finished yet. It's not production-ready. It's not even testing-ready. Later on I'm going to explain why I decided to discuss it anyway, even under such sub-optimal circumstances.

Video

I've been told that one would rather watch a video about the CMakeSL than read such a long article. For the sake of convenience you can watch the following video: https://youtu.be/dDXYf3FqO2g (I've just uploaded it, so a better quality is going to be available when youtube processes it).

The video is quite long, but keep in mind that you'll find only a pratical introduction there. Meanwhile, this article is meant to carry more information about the reasons, the plans etc.

Why

I'm a C++ programmer. I've been programming for food for about three years. CMake has been involved in almost every project I've worked on, and in almost every one of them I had to change it, add new stuff and maintain the already written code. Generally, I consider CMake a great tool. It simplifies and helps with a lot of tasks around build systems. On the other hand, I have struggled with it every time I had to make a non-trivial change or addition. This was caused mostly by the scripting language that CMake uses and implements.

How

CMakeSL itself is a set of libraries. It's written in C++17 and that's the only dependency. No external libraries are used (besides the googletest for obvious reasons). C++ has been chosen to easily integrate CMakeSL with the current CMake codebase. C++17 specifically has been chosen for std::variant, std::optional, std::string_view and other C++17 life-savers.

High-level idea how it's supposed to work

The only thing that CMakeSL changes is the scripting language, not generation, not building, only how users write scripts. In other words, the new language is executed at the configure step. Generation and building remain untouched.

The syntax and language design of CMakeSL are inspired mostly by C++. It's statically typed, with scopes, functions, classes, references etc. You can read more about this in the User Guide, in the doc directory of CMakeSL repo.

Another advantage of a C++ish taste is that you get syntax highlight and code formatting for free (clang-format is everywhere nowadays).

Integration with CMake

For now, I want to separate CMake and CMakeSL as much as possible. That's why CMakeSL sits in a completely separate repository.

To make CMakeSL usable from a CMake binary, some changes have to be made. Those changes are stored in the cmake_integration/cmake_changes.patch, in the CMakeSL repository. In the How to section, there is a full instruction on how to build this.

One note about CMake codebase changes. I wanted to integrate CMakeSL with CMake with lowest possible cost, in term of an amount of work. I'm aware that I don't know CMake codebase that much, to be able to integrate CMakeSL in a proper way. If CMakeSL goes of the ground, the integration will be done properly.

Code architecture

CMakeSL, besides other things, introduces an exec library, which is an entry point for execution of scripts, i.e., CMake uses it to execute scripts.

Another thing that CMakeSL introduces is a cmake_facade interface. CMake implements it and passes an instance of it to the exec library. CMakeSL then uses it to communicate back with the complex CMake code environment (like creating project, libraries, executable, getting CMake version etc.). Here you can see it in a simple diagram:

alt text

Current status

Currently, CMakeSL is is more of a working POC than a complete library. Nevertheless, I believe it's a good starting point. Here are some things that you can do with it.

CMake-related:

  • create a project
  • add executable to the project
  • add library to the project
  • link executables and libraries with other libraries
  • add subdirectory

Language-related:

  • functions (with overloading)
  • variables
  • classes with methods and members
  • references
  • builtin types (bool, int, double, string, version, project, executable, library and a GENERIC list (I'm personally proud of this one))

Tool-related (see examples in CMakeSL repo):

  • syntax completer
  • indexer

You possibly think it looks very good and you may imagine that it's a lot, but please keep in mind, that all this is POC. When I say that you have a project class where you can create executables and libraries, be aware that it's very limited. They work. You can build an exec or library but these are not fully working features that you know from the CMake.

It's the same with tools. Indexer and syntax completion are not those from, say, clang.

Why do I release a not-finished project?

It's simple. There is just so much work to do, that I'm simply not able to do it on my own. I've been writing CMakeSL almost every day after my daily work and on weekends and it's still not ready for anything. I can't afford myself to quit my job and work full-time on this. That's why I decided to reach out to the community and people willing to help (:

Future plans

Currently, I am working on making CMake with CMakeSL support compilable on Windows (CMakeSL itself works), as wel as on Travis CI integration (yep, no CI yet). Then, I am planning to work on tests, to improve existing ones and create new ones, in order to increase confidence while making changes. This will take a while. I'm not sure as to what comes after that. It depends on how you react to the project as it stands now. If there is interest, if people like this and are willing to help, the plan and work will come. If there is no interest, I'll probably implement it on my own to some extent and start working on some other project.

One huge topic that has to be handled is making old CMake scripts usable by the CMakeSL. I don't want to make the CMakeSL backward-compatible. I'm talking about a situation when you write a CMakeSL script and you would want to use an external library that doesn't support CMakeSL yet. You have only the old CMakeLists.

A few ideas that I would like to implement in the language itself which are not even touched upon here:

  • enums
  • switch, for, range-based for etc. (yes those are not implemented yet)
  • unary operators
  • result builtin type. Similar to the one from Rust
  • optional, variant, map, set etc. builtin types
  • namespaces
  • modules
  • and a lot more...

Issues and pull requests are going to be maintained at the GitHub. Additionally I'm considering making a Trello board for a rough roadmap (similar to the one UE has: https://trello.com/b/TTAVI7Ny/ue4-roadmap).

How to

Building CMake with CMakeSL support

# Clone CMake codebase
git clone https://gitlab.kitware.com/cmake/cmake.git
cd cmake
# CMakeSL bases on this particular release
git checkout v3.14.3

# Clone CMakeSL in the `Source` directory
cd Source
git clone https://github.com/stryku/cmakesl
cd cmakesl
git checkout v0.0

# Apply needed changes to CMake code
cd ../..
git apply Source/cmakesl/cmake_integration/cmake_changes.patch

# Build CMake. C++17 compiler is required
cd ..
mkdir build
mkdir install
cd build
cmake ../cmake -DCMAKE_CXX_COMPILER=<compiler supporting C++17> -DCMAKE_INSTALL_PREFIX=../install
make install -j
cd ..
# Now, in install/bin you have the `cmake` binary that supports CMakeSL

An alternative way to build CMake is to use a ready-made script from the scripts directory in the CMakeSL repo.

wget https://raw.githubusercontent.com/stryku/cmakesl/master/scripts/build_cmake.sh
chmod +x build_cmake.sh
./build_cmake.sh clang++-7

CMakeSL hello world

# Assuming that we're in the root working directory (the one with cmake, build and install)
cd install/bin
mkdir hello_world
cd hello_world
# Create a hello world C++ file
echo "#include <iostream>

int main()
{
    std::cout << \"Hello CMakeSL world!\n\";
}" >> main.cpp

# Create a CMakeSL script that creates an executable
echo "
int main()
{
    cmake_minimum_required(version(3, 14, 3));

    project hello_world = project(\"hello world\");

    list<string> sources = { \"main.cpp\" }
    hello_world.add_executable(\"hello_world_exec\", sources);

    return 0;
}" >> CMakeLists.cmsl

# Run cmake binary
cd ..
mkdir build
cd build
# Use the previously built CMake binary
./../cmake ../hello_world
make

# Run the hello world executable
./hello_world_exec

You can find a more complex example in the examples directory in the CMakeSL repo.

Discussion and links

The repository: https://github.com/stryku/cmakesl

I case of any thoughts, questions or suggestions, please leave a comment in one these places or simply send me an email. I'm curious what do you guys think about all this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment