Jan 2, 2016

[cmake] Syntax and concepts. [Note]

Target:
    1. executable: add_executable()
    2. library: add_library()
    3. custom target containing custom commands
 

Library type:
    1. SHARED
    2. STATIC
    3. MODULE # Used as dlopen
    4. OBJECT #  It defines a non-archival collection of object files resulting from compiling the given source files.
        OBJECT libraries may only be used locally as sources in a buildsystem – they may not be installed, exported, or used in the right hand side of target_link_libraries().
     
Target:
target_include_directories  # -I
    Specify include directories to use when compiling a given target. The named <target> must have been created by a command such as add_executable() or add_library() and must not be an IMPORTED target.
INCLUDE_DIRECTORIES : List of preprocessor include file search directories.
INTERFACE_INCLUDE_DIRECTORIES : List of public include directories requirements for a library.
    Targets may populate this property to publish the include directories required to compile against the headers for the target.

target_compile_definitions # -D
    Specify compile definitions to use when compiling a given <target>. The named <target> must have been created by a command such as add_executable() or add_library() and must not be an Imported Target.
COMPILE_DEFINITIONS : Preprocessor definitions for compiling a target’s sources.
INTERFACE_COMPILE_DEFINITIONS : List of public compile definitions requirements for a library.

target_compile_options #
    Specify compile options to use when compiling a given target. The named <target> must have been created by a command such as add_executable() or add_library() and must not be an IMPORTED Target.
    If BEFORE is specified, the content will be prepended to the property instead of being appended.
COMPILE_OPTIONS : List of options to pass to the compiler.
INTERFACE_COMPILE_OPTIONS : List of public compile options requirements for a library.


PUBLIC, PRIVATE and INTERFACE explained:
http://stackoverflow.com/a/28305481
Therefore, suppose you are creating a library A that uses some Boost headers. You would do:
target_include_directories(A PRIVATE ${Boost_INCLUDE_DIRS}) if you only use those Boost headers inside your source files (.cpp) or private header files (.h).
target_include_directories(A INTERFACE ${Boost_INCLUDE_DIRS}) if you don't use those Boost headers inside your source files (therefore, not needing them to compile A). I can't actually think of a real-world example for this.
target_include_directories(A PUBLIC ${Boost_INCLUDE_DIRS}) if you use those Boost headers in your public header files, which are included BOTH in some of A's source files and might also be included in any other client of your A library.
 

https://cmake.org/cmake/help/latest/variable/BUILD_SHARED_LIBS.html#variable:BUILD_SHARED_LIBS
BUILD_SHARED_LIBS : Global flag to cause add_library() to create shared libraries if on.

https://cmake.org/cmake/help/latest/command/target_link_libraries.html#command:target_link_libraries
target_link_libraries

Dependency:
    target_link_libraries(executable library)

 
 
--------------------
Syntax:
https://cmake.org/Wiki/CMake/Language_Syntax
https://cmake.org/Wiki/CMake:VariablesListsStrings
https://cmake.org/cmake/help/v3.0/manual/cmake-language.7.html#syntax

Variable doesn't need to be declared.
All variables in CMake are global.
Global means that the variables exist in the file where they have been created,
    in all subdirectories connected using ADD_SUBDIRECTORY() or SUBDIRS(), and in all included files in any of these directories.
    They don't propagate up to the parent directories. Also if the value of a variable is changed in a subdirectory, the change doesn't propagate up to the variable in the parent directory.

All variables are of the type string.  
CMake can deal also with lists. If a string contains semicolons, these semicolons can be interpreted as separators of string values.


All these are 'false' in CMake:
OFF
FALSE
N
NO
0
"" (empty string)
a null variable, such as produced by "set(variable)".
NOTFOUND
any string ending in -NOTFOUND


All these are 'true' in CMake:
ON
TRUE
Y
YE
YES
1
everything not listed under false


The CMake cache:
CMake uses an on-disk cache file to store variables and their values for later runs.
This file is located in CMAKE_BINARY_DIR and is named CMakeCache.txt.
The variables in this file are global to the whole build tree.
Most configure-checks save their result in this file, so they don't have to be executed again on later CMake runs.


Command names in uppercase.
Arguments are case sensitive.
Commands are procedure calls and cannot return values.
However, you may pass the name of a global variable to some commands, and those commands will store the result there.


FOREACH command, the loop variable of which is local only to the FOREACH body.
The parameters (including ARG0, ARG1, ARG2, ARGC, ARGN, and ARGV) of user defined macros are not variables, per se;
    their values must always be used directly: IF(${some_parameter}) instead of IF(some_parameter).


Functions, which are essentially macros that have local scope and use real variables (even ARG0, ARG1, ARGC, ARGN, and ARGV are treated as real variables);
IF(some_parameter) is perfectly acceptable.
Global variables are read-only within functions.
A variable is set within a function body, that variable only has local scope, masking any similarly named global variable; outside of the function body,
    the global variables remain unchanged.
 
IF command provides conditionals, while the WHILE command provides a loop. These two commands also provide the way to evaluate boolean expressions.
CMake executes an IF command, it evaluates the arguments to get a boolean condition.
If the condition is true, it runs the command between the IF and matching ENDIF commands, else it skips them.

CMake is very strict, and requires the matching IF and ENDIF (or WHILE and ENDWHILE) commands to have the same arguments.

Does IF( number GREATER 10 ) mean the same as IF( ${number} GREATER 10 )? Actually it does, if number is a variable.
Some operations in boolean expressions will accept either a variable name or a value. If the name matches a variable name,
then CMake uses that variable's value; but if the name does not match a variable name, then CMake uses the direct value.

The first argument to the SET command is a variable name, not a substitution. SET wants to know the name of the variable to set, not the variable's current value.

We can substitute the value of an environment variable. The syntax is $ENV{name}.
Note that "ENV" is the only permitted hash.
It is possible to set an environment variable:
SET( ENV{PATH} /bin:/usr/bin ) # use a minimal PATH


Command:
cmake -P script
cmake -P /dev/stdin # Ctrl-D

# This is a comment.

MESSAGE( hi ) # displays "hi"
message( hi ) # displays "hi" again
message( HI ) # displays "HI"

MATH( EXPR x "3 + 3" ) # stores the result of 3 + 3 in x
MESSAGE( "x is ${x}" ) # displays "x is 6"
                                         # using quotes so MESSAGE receives only one argument

SET(VAR_NAME VALUE) # can dereference VAR_NAME by ${VAR_NAME}

SET( x a b c   ) # stores "a;b;c" in x      (without quotes)
SET( y "a b c" ) # stores "a b c" in y      (without quotes)
MESSAGE( a b c ) # prints "abc"   to stdout (without quotes)
MESSAGE( ${x} )  # prints "abc"   to stdout (without quotes)
MESSAGE("${x}")  # prints "a;b;c" to stdout (without quotes)
MESSAGE( ${y} )  # prints "a b c" to stdout (without quotes)
MESSAGE("${y}")  # prints "a b c" to stdout (without quotes)

all equivalent:
SET( x a b c )
SET( x a;b;c )
SET( x "a;b;c" )
SET( x;a;b;c )

SET( x y A B C )              # stores "y;A;B;C" in x (without quote)
SET( ${x} )                   # => SET( y;A;B;C ) => SET( y A B C)
MESSAGE( ${y} )               # prints "ABC" to stdout (without quotes)
SET( y x )                    # stores "x" in y (without quotes)
SET( ${y} y = x )             # => SET( x y )
MESSAGE( "\${x} = '${x}'" )   # prints "${x} = 'y;=;x'" to stdout (without quotes)
SET( y ${x} )                 # => SET( y y = x ) => stores "y;=;x" in y (without quotes)
MESSAGE( ${y} )               # prints "y=x" to stdout (without quotes)

equivalent:
SET( x "" )
UNSET( x )


no go:
SET( command MESSAGE )
${command}( hi )
# syntax error

instead:
SET( command MESSAGE )
# ${command}( hi )
FILE( WRITE temp "${command}( hi )" ) # writes "MESSAGE( hi )" to ./temp
INCLUDE( temp )                       # ./temp is an unsafe temporary file...
FILE( REMOVE temp )

CMake splits arguments unless you use quotation marks or escapes:
MESSAGE(This is practice.)             # prints "Thisispractice."
MESSAGE(  This   is    practice.     ) # prints "Thisispractice."
MESSAGE( This;is;practice. )           # prints "Thisispractice."

MESSAGE( "This is practice." )  # prints "This is practice."
MESSAGE( "This;is;practice." )  # prints "This;is;practice."
MESSAGE( "Hi. ) MESSAGE( x )" ) # prints "Hi. ) MESSAGE( x )"


Escapes:
A backslash \ in the arguments to a command will start an escape sequence. To use literally any of "()#$^,
escape the character with a backslash. You may also escape a space (instead of quoting it) and you may use \\ for a literal backslash.

MESSAGE( \# not a comment )
MESSAGE( \${NotAnExpansion} )
SET( rightparen \) )


SET( number 4 )
# if ${number} is greater than 10
IF( number GREATER 10 )
  MESSAGE( "The number ${number} is too large." )
ENDIF( number GREATER 10 )


# while ${number} is between 0 and 11
WHILE( number GREATER 0 AND number LESS 11 )
  MESSAGE( "hi ${number}")
  MATH( EXPR number "${number} - 1" ) # decrement number
ENDWHILE( number GREATER 0 AND number LESS 11 )


SET( letters a b c d ) # sets letters to "a;b;c;d"

SET( expression 4 LESS 10 ) # ${expression} is now "4;LESS;10"
IF( ${expression} )         # expands to IF( 4;LESS;10 )
  MESSAGE( "CMake believes that 4 is less than 10." )
ENDIF( ${expression} )

SET( varname number ) # sets varname to "number"
SET( ${varname} 4 )   # sets number to "4"


CMake may access environment variables:
SET( ENV{PATH} /bin:/usr/bin ) # use a minimal PATH

Recursive substitutions permit indirect variables:
SET( varname x )
SET( x 6 )
MESSAGE( "${varname} is ${${varname}}" ) # displays "x is 6"

No comments:

Post a Comment

Note: Only a member of this blog may post a comment.