toeb / cmakepp

An Enhancement Suite for the CMake Build System
Other
432 stars 37 forks source link

cmakepp logo

A CMake Enhancement Suite

Travis branch GitHub stars GitHub forks GitHub issues Build Status Project Stats

Usage

Look through the files in the package. Most functions will be commented and the other's usage can be inferred. All functions are available as soon as you include the cmakepp.cmake file. To find functionality browse the README.md files throughout this project.

Feature Overview

cmakepp has a lot of different functions. I tried to subdivide them into some meaningful sections.

Samples

I have developed some samples to show off cmakepp's capabilities. Here you can find an overview of these samples

https://github.com/open-source-parsers/jsoncpp/archive/1.6.0.tar.gz https://github.com/leethomason/tinyxml2/archive/2.2.0.tar.gz https://yaml-cpp.googlecode.com/files/yaml-cpp-0.5.1.tar.gz

Getting cmakepp

You have multiple options to install cmakepp the only prerequisite for all options is that CMake is installed with a version >=2.8.12. cmakepp will also work with version less than 2.8.12 however some functions might fail.

Install by Console

For ease of use I provide you with simple copy paste code for your console of choice. These scripts download the install.cmake file and execute it. This file in turn downloads cmakepp and adds itself to your os (creating aliases and setting a environment variable - which allow you to use icmakepp and cmakepp cli from the console).

Bash

#!bin/bash
wget https://raw.github.com/toeb/cmakepp/master/install.cmake && cmake -P install.cmake && rm install.cmake

Powershell

((new-object net.webclient).DownloadString('https://raw.github.com/toeb/cmakepp/master/install.cmake')) |`
out-file -Encoding ascii install.cmake; `
cmake -P install.cmake; `
rm install.cmake;

Install by Downloading a Release

You can go ahead and download the current release from here. A release supplies you with a standalone version of cmakepp which contains every function of cmakepp. This standalone file can be included in any of your CMake scripts.

The following code shows you how you can retrieve and include it in any of your script files.

## downloads and includes `cmakepp.cmake` 
if(NOT EXISTS "cmakepp.cmake")
  file(DOWNLOAD "https://github.com/toeb/cmakepp/releases/download/v0.0.4/cmakepp.cmake" "cmakepp.cmake")
endif()
include("cmakepp.cmake")

Manually setting up aliases

cmake -P ./cmakepp.cmake cmakepp_setup_environment

After You run this and relogin/repoen your console/resource your .bashrc you will have access to the alias cmakepp, icmakepp, pkg, cml. Also the environment variable CMAKEPP_PATH will be set to the location were cmakepp.cmake resides.

Testing

To test the code (alot is tested but not all) run the following in the root dir of cmakepp this takes long :)

cmake -P build/script.cmake 

Developing

If you want to help to develope cmakepp or want to develope CMake scripts which use cmakepp you can do the following:

Developement Process

I have two persistant branches: master and devel. Then there are an arbitrary amount of volatile branches which are used to develope features / remote store developements. The master branch is only merged from devel and always is always stable - ie the build server determines that all tests were successfull. The devel branch is also built build servers but may sometime be in the failed state. The volatile branches are just used to develop and are not built - as to not clutter up the build servers with uneccessary builds.

Contributing

I would be very happy If you choose to contribute to cmakepp. You can open any issue on github and I will try to reply as soon as possible. I care about any feature you want implemented, bug you want squashed, or modification.

If you want to change something you may send pull requests through github. Normally I will check them quickly and travis-ci will build them. I suggest you run all tests using the sublime project before you create a pull request to see if anything breaks. (the master branch will have to pass the tests)

Also if you want to support me financially for all the hardwork - consider donating a couple of $ Click here to lend your support to: cmakepp  and make a donation at pledgie.com !

Developer Guidlines

I am a bit a hypocrit. I am trying to adhere to these rules though:

Implementation Notes

Formalisms

Note: This section is incomplete but will give you an idea how I formally define data and functions.

To describe cmake functions I use formalisms which I found most useful they should be intuitively understandable but here I want to describe them in detail.

Returning values

Related Functions

A CMake function can return values by accessing it's parent scope. Normally one does the following to return a value

  function(myfunc result)
    set(${result} "return value" PARENT_SCOPE)
  endfunction()
  myfunc(res)
  assert(${res} STREQUAL "return value")

This type of programming causes problems when nesting functions as one has to return every return value that a nested function returns. Doing this automatically would cause alot of overhead as the whole scope would have to be parsed to see which values are new after a function call.

A cleaner alternative known from many programming languages is using a return value. I propose and have implemented the following pattern to work around the missing function return values of cmake.

  function(myfunc)
    return("return_value")
  endfunction()
  myfunc()
  ans(res)
  # the __ans var is used as a register
  assert(${__ans} STREQUAL "return value")
  assert(${res} STREQUAL "return value")

This is possible by overwriting CMakes default return() function with a macro. It accepts variables and will call set(__ans ${ARGN} PARENT_SCOPE) so after the call to myfunc() the scope will contain the variable __ans. using the ans(<var>) function is a shorthand for set(<var> ${__ans}).

Caveats

Alternatives

cmakepp Console Client

cmakepp can be used as a platform independent console application. When you start cmakepp.cmake in script mode it parse the passed command line arguments and execute the specified cmakepp function returning the value in a serialization format. When you install cmakepp it will create an alias for cmake -P /path/to/cmakepp.cmake called cmakepp.

## return content of this directory using the cmakepp.cmake file
> cmake -P /path/to/cmakepp.cmake glob *.cmake --relative
[
 "cmakepp.cmake",
 "install.cmake",
 "package.cmake"
]

## perform a http GET request using the cmakepp alias
> cmakepp http_get http://httpbin.org/get?key=value --json
{
 "args":{
  "key":"value"
 },
 "headers":{
  "Accept":"*/*",
  "Host":"httpbin.org",
  "User-Agent":"curl/7.38.0"
 },
 "origin":"85.180.182.43",
 "url":"http://httpbin.org/get?key=value"
}

## parse an uri using the cmakepp alias
> cmakepp uri http+https://toeb:pass@www.example.com/path/to/file.ext?key=value&key2.subkey=value2 --select "scheme: @scheme key2.subkey: @params.key2.subkey"
"scheme: http+https key2.subkey: value2"

Interactive CMake Shell

If you want to learn try or learn cmake and cmakepp you can use the interactive cmake shell by launching cmake -P icmakepp.cmake which gives you a prompt with the all functions available in cmakepp and cmake in general.

icmakepp allows you to enter valid cmake and also a more lazily you can neglect to enter the parentheses around functions e.g. cd my/path -> cd(my/path)

Since console interaction is complicated with cmake and cmake itself is not very general purpose by design the interactive cmake shell is not as user friendly as it should be. If you input an error the shell will terminate because cmake terminates. This problem might be addressed in the future (I have an idea however not the time to implement and test it) Example:

> ./icmakepp.sh
icmakepp> cd /usr/tobi
"/usr/tobi"
icmakepp> pwd
"/usr/tobi"
icmakepp> @echo off
echo is now off
icmakepp> pwd
icmakepp> message("${ANS}")
/usr/tobi
icmakepp> @echo on
echo is now on
icmakepp> function(myfunc name)\  # <-- backslash allows multiline input
          message("hello ${name}") \
          obj("{name: $name}")\
          ans(person)\
          return(${person})\
        endfunction()
"/usr/tobi"                 # <-- the last output of any function is always repeated. 
icmakepp> myfunc Tobi
hello Tobi          # <-- output in function using message
{"name":"Tobi"}       # <-- json serialized return value of function
icmakepp> quit
icmakepp is quitting
>