Computer Scientist

Tuesday, 10 October 2017

CMake Learning 1

Here is a snippet collect of learning CMake tool, which replaces my autoconf tool sets.

This is not a complete and clean version. A final cleanse and restructure are required,


Basic Usage:
  1. CMake is case insensitive. 
  2. Variables: 
    1. Variable: ${VAR}. set is used to set variable values: set (Foo a b c).
    2. command(${Foo}) = command(a b c). command("${Foo}") = command("a b c").
    3. $ENV{VAR}: is for accessing to system environment variables.
  3. CMakefile:
    1. # means a start of a comment line in the file.
    2. add_executable: build executable using the given list of files.
    3. find_library: look for specific libraries with different NAMES and in different PATHS. 
    4. target_link_library: link libraries to executables.
  4. Run CMake: 
    1. Two directories: Source directory and Build directory
    2.  In-source build: source directory and build directory are the same.

Main Structures:
The main components in CMake are implemented as C++ classes, which are then referenced in many of CMake commands.

The following is the structure of the main CMake components:


  1. Source files: C or C++ source code.
  2. Targets: is typically an executable or library.
  3. Directory: each directory contains one or several targets which are built from the source files in the directory.
  4. Generators: each directory has a local generator that is responsible for generating the Makefiles or project files for the directory. All local generators share a common global generators to oversee the build process.
For example, under Visual Studio 7, the global generator creates a solution file for the entire project while the local generators create a project file for each target in their directory.
In Unix makefile generator, the local generators create the makefiles in each sub-directory and the global generator creates the top-level makefile in the root directory.

Mechanism of CMake commands:
  • There are two main parts for each command: InitialPass method and FinalPass method. 
  • InitialPass method accepts arguments and local generator (cmMakefile instance). Apply the command using the arguments and store the results in the provided cmMakefile instance.
  • FinalPass method runs only after the invocation of InitialPass methods from all commands. Not all commands have FinalPass. For some commands, the global information is required, which may not be available in the InitialPass phase.

Targets:
  • add_library, add_executable and add_custom_target command creates a target. eg: add_library (foo STATIC foo1.c foo2.c) [created a static library called foo]
    • STATIC, SHARED, MODULE are available options. In most system, SHARED and MODULE are the same but not in Mac OS X. 
    • If it is blank, the variable BUILD_SHARED_LIBS controls whether a shared or static library should be built. By default, CMake builds a static library.
  • set_target_property and get_target_property commands to manipulate target's properties.
  • target_link_libraries command to denote a list of libraries that the target link against. Accepted format: libraries, full path to libraries or name of a library from an add_library command.

Source Files:

  • set_source_files_properties and get_source_file_property are to access a source file's properties.
    • COMPLILE_FLAGS
    • GENERATED
    • OBJECT_DEPENDS
    • ABSTRACTWRAP_EXCLUDE
Variables:

  • Variables have scope which is after its definition.
  • Two examples of scope:
    function (foo)
        message(${test} # output 1 here
        set (test 2)
        messgae(${test} # output 2 here 
    endfunction()

    set(test 1)
    foo()
    message (${test}) # This is still a 1.

vs

    function (foo)
        message(${test} # output 1 here
        set (test 2 PATENT_SCOPE)
        messgae(${test} # output 2 here 
    endfunction()

    set(test 1)
    foo()
    message (${test}) # This is 2 now.


  • if command:
    set (FOO 1)
 
    if (${FOO} LESS 2)
        set (FOO 2)
    else (${FOO} LESS 2)
        set (FOO 3)
    endif(${FOO} LESS 2
  • loop command:

    set (items_to_buy apple, orange pear beer)

    foreeach (item ${iterm_to_buy})
        message("Don't forget to buy one ${itme}")
    endforeeach ()

Cache Entries:

  • In case the user is allowed to build the project to set a variable from the CMake user interface, the variable must be a cache entry.
  • A cache file is produced in the build directory, which stores the user's selections and choices as its main purpose.
  • option (USE_JPEG "Do you want to use the jpeg library"). This command creates a variable called USE_JPEG and put it into the cache.
  • Ways of create a cache entry: 
    • option
    • find_file
    • set using CACHE option: set (USE_JPEG ON CACHE BOOL "include jpeg support?"), the following variable types must be used for GUI to control how that variable is set and displayed.
      • BOOL
      • PATH
      • FILEPATH
      • STRING
  • Another purpose of using cache is to store key variables that are expensive to determine, such as CMAKE_WORDS_BIGENDIAN, which needs to compile and run a program to determine its value. This is to prevent having to recompute them every time CMake is run.
  • mark_as_advanced is used to set a cache entry as an advanced cache, which will not be shown at first when the CMake GUI is run. The advanced cache entries are other options that the user can modify, but typically will not.
  • the value of cache entry can be restriced to a limited set of predefined options (pull down list) by setting it's property: 
    • set (CRYPTOBACKEND "OpenSSL" CACHE STRING "Select a cryptography backend")
    • set_property (CACHE CRYPTOBACKEND PROPERTY STRINGS "OpenSSL" "LibTomCrypt" "LibDES")
  • The following points are worth to pointing: 
    • Variables in cache can still be overridden in a CMakeLists file using set without CACHE optoin.
    • Cache values are checked only if the variable is not found in the current cmMakefile instance before CMakeLists file processing begins.
    • The set command will set the variable for processing the current CMakeLists file without changing the value in the cache.
    • "Once a variable is in the cache, its "cache" value cannot normally be modified from a CMakeLists file. The reasoning behind this is that once CMake has put the variable into the cache with its initial value, the user may then modify that value from the GUI. If the next invocation of CMake overwrote their change back to the set value, the user would never be able to make a change that CMake wouldn't overwrite. So a set (FOO ON CACHE BOOL "doc") comman will typically only do something when the cache doesn't have the variable in it. Once the variable is in the cache, that command will have no effect."
Build Configurations:

  • Supported build configurations: 
    • Debug, has basic debug flags turned on.
    • Release, has basic optimizations turned on.
    • MinSizeRel, has the flags that produce the smallest object code, but not necessarily the fastest code.
    • RelWithDebInfo, builds an optimised build with debug information as well.
  • For Visual Studio IDE, CMAKE_CONFIGURATION_TYPES is used to tell CMake which configurations to put in the workspace.
  • For Makefile, only one configuration can be active , whcih is specified by the CMAKE_BUILD_TYPE variable. The corresponding flags (CMAKE_CXX_FLAGS_<ConfigName>) are added to the compile lines. Make file doesn't create subdirectories for object files. So to build both debug and release trees, two separated build directories are required and use the out of source build feature of CMake, for example: (ccmake ../MyProject -DCMAKE_BUILD_TYPE:STRING=Debug) or (ccmake ../MyProject -DCMAKE_BUILD_TYPE:STRING=Release)




No comments:

Post a Comment