Commit 1acbb5c6 authored by Dominik Charousset's avatar Dominik Charousset

Merge branch 'topic/integrate-manual'

parents 5042ac89 f0de546e
...@@ -597,78 +597,60 @@ if(NOT CAF_NO_UNIT_TESTS) ...@@ -597,78 +597,60 @@ if(NOT CAF_NO_UNIT_TESTS)
endif() endif()
################################################################################ # -- Fetch branch name and SHA if available ------------------------------------
# Doxygen setup #
################################################################################
# check for doxygen and add custom "doc" target to Makefile
find_package(Doxygen)
if(DOXYGEN_FOUND)
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/doc/Doxyfile.in"
"${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile"
@ONLY)
add_custom_target(doc "${DOXYGEN_EXECUTABLE}"
"${CMAKE_HOME_DIRECTORY}/Doxyfile"
WORKING_DIRECTORY "${CMAKE_HOME_DIRECTORY}"
COMMENT "Generating API documentation with Doxygen"
VERBATIM)
endif(DOXYGEN_FOUND)
################################################################################ if(EXISTS "release.txt")
# Manual setup # file(READ "release.txt" CAF_VESION)
################################################################################ else()
set(CAF_RELEASE "${CAF_VERSION}")
set(MANUAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/manual") find_package(Git QUIET)
if(EXISTS "${MANUAL_DIR}" if(GIT_FOUND)
AND EXISTS "${MANUAL_DIR}/variables.tex.in" # retrieve current branch name for CAF
AND EXISTS "${MANUAL_DIR}/conf.py.in") execute_process(COMMAND ${GIT_EXECUTABLE} rev-parse --abbrev-ref HEAD
# retrieve current branch name for CAF
execute_process(COMMAND git rev-parse --abbrev-ref HEAD
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
OUTPUT_VARIABLE GIT_BRANCH
OUTPUT_STRIP_TRAILING_WHITESPACE)
# retrieve current SHA1 hash for CAF
execute_process(COMMAND git log --pretty=format:%h -n 1
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
OUTPUT_VARIABLE CAF_SHA
OUTPUT_STRIP_TRAILING_WHITESPACE)
# retrieve current SHA1 hash for the Manual
execute_process(COMMAND git log --pretty=format:%h -n 1
WORKING_DIRECTORY ${MANUAL_DIR}
OUTPUT_VARIABLE CAF_MANUAL_SHA
OUTPUT_STRIP_TRAILING_WHITESPACE)
if(${GIT_BRANCH} STREQUAL "master")
# retrieve current tag name for CAF
execute_process(COMMAND git describe --tags --contains ${CAF_SHA}
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
RESULT_VARIABLE GIT_TAG_RES RESULT_VARIABLE gitBranchResult
OUTPUT_VARIABLE GIT_TAG OUTPUT_VARIABLE gitBranch
ERROR_QUIET ERROR_QUIET
OUTPUT_STRIP_TRAILING_WHITESPACE) OUTPUT_STRIP_TRAILING_WHITESPACE)
# prefer tag name over auto-generated version # retrieve current SHA1 hash for CAF
if(GIT_TAG_RES STREQUAL "0") execute_process(COMMAND ${GIT_EXECUTABLE} log --pretty=format:%h -n 1
set(CAF_RELEASE "${GIT_TAG}") WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
else() RESULT_VARIABLE gitShaResult
set(CAF_RELEASE "${CAF_VERSION}") OUTPUT_VARIABLE gitSha
ERROR_QUIET
OUTPUT_STRIP_TRAILING_WHITESPACE)
if(gitBranchResult EQUAL 0 AND gitShaResult EQUAL 0)
# generate semantic CAF version for manual
set(CAF_RELEASE "${CAF_VERSION}+exp.sha.${gitSha}")
# check whether we're building the manual for a stable release
if(gitBranch STREQUAL "master")
# retrieve current tag name for CAF
execute_process(COMMAND ${GIT_EXECUTABLE} describe --tags --contains ${gitSha}
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
RESULT_VARIABLE gitTagResult
OUTPUT_VARIABLE gitTag
ERROR_QUIET
OUTPUT_STRIP_TRAILING_WHITESPACE)
# tags indicate stable releases -> use tag name as release version
if(gitTagResult EQUAL 0)
set(CAF_RELEASE "${gitTag}")
endif()
endif()
endif() endif()
else()
set(CAF_RELEASE "${CAF_VERSION}+exp.sha.${CAF_SHA}")
endif() endif()
MESSAGE(STATUS "Set manual version to ${CAF_RELEASE}")
configure_file("${MANUAL_DIR}/variables.tex.in"
"${MANUAL_DIR}/variables.tex"
IMMEDIATE @ONLY)
configure_file("${MANUAL_DIR}/conf.py.in"
"${MANUAL_DIR}/conf.py"
IMMEDIATE @ONLY)
configure_file("${MANUAL_DIR}/index_header.rst.in"
"${MANUAL_DIR}/index_header.rst"
IMMEDIATE @ONLY)
configure_file("${MANUAL_DIR}/index_footer.rst.in"
"${MANUAL_DIR}/index_footer.rst"
IMMEDIATE @ONLY)
endif() endif()
message(STATUS "Set release version for all documentation to ${CAF_RELEASE}.")
# -- Setup for building manual and API documentation ---------------------------
# we need the examples and some headers relative to the build/doc/tex directory
file(COPY examples/ DESTINATION examples)
file(COPY libcaf_core/caf/exit_reason.hpp DESTINATION libcaf_core/caf/)
file(COPY libcaf_core/caf/sec.hpp DESTINATION libcaf_core/caf/)
add_subdirectory(doc)
################################################################################ ################################################################################
# Add additional project files to GUI # # Add additional project files to GUI #
################################################################################ ################################################################################
......
...@@ -198,11 +198,12 @@ pipeline { ...@@ -198,11 +198,12 @@ pipeline {
deleteDir() deleteDir()
dir('caf-sources') { dir('caf-sources') {
checkout scm checkout scm
sh './scripts/get-release-version.sh'
} }
stash includes: 'caf-sources/**', name: 'caf-sources' stash includes: 'caf-sources/**', name: 'caf-sources'
} }
} }
// Start builds. /*
stage('Builds') { stage('Builds') {
steps { steps {
script { script {
...@@ -222,6 +223,54 @@ pipeline { ...@@ -222,6 +223,54 @@ pipeline {
} }
} }
} }
*/
stage('Documentation') {
agent { label 'pandoc' }
steps {
deleteDir()
unstash('caf-sources')
dir('caf-sources') {
// Configure and build.
cmakeBuild([
buildDir: 'build',
installation: 'cmake in search path',
sourceDir: '.',
steps: [[
args: '--target doc',
withCmake: true,
]],
])
sshagent(['84d71a75-cbb6-489a-8f4c-d0e2793201e9']) {
sh '''
if [ "$(cat branch.txt)" = "master" ]; then
rsync -e "ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null" -r -z --delete build/doc/html/ www.inet.haw-hamburg.de:/users/www/www.actor-framework.org/html/doc
scp -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null build/doc/manual.pdf www.inet.haw-hamburg.de:/users/www/www.actor-framework.org/html/pdf/manual.pdf
fi
'''
}
}
dir('read-the-docs') {
git([
credentialsId: '9b054212-9bb4-41fd-ad8e-b7d47495303f',
url: 'git@github.com:actor-framework/read-the-docs.git',
])
sh '''
if [ "$(cat ../caf-sources/branch.txt)" = "master" ]; then
cp ../caf-sources/build/doc/rst/* .
if [ -n "$(git status --porcelain)" ]; then
git add .
git commit -m "Update Manual"
git push --set-upstream origin master
if [ -z "$(grep 'exp.sha' ../caf-sources/release.txt)" ] ; then
git tag $(cat ../caf-sources/release.txt)
git push origin $(cat ../caf-sources/release.txt)
fi
fi
fi
'''
}
}
}
} }
post { post {
success { success {
......
...@@ -119,6 +119,12 @@ A SNocs workspace is provided by GitHub user ...@@ -119,6 +119,12 @@ A SNocs workspace is provided by GitHub user
* FreeBSD 10 * FreeBSD 10
* Windows >= 7 (currently static builds only) * Windows >= 7 (currently static builds only)
## Optional Dependencies
* Doxygen (for the `doxygen` target)
* LaTeX (for the `manual` target)
* Pandoc and Python with pandocfilters (for the `rst` target)
## Scientific Use ## Scientific Use
If you use CAF in a scientific context, please use one of the following citations: If you use CAF in a scientific context, please use one of the following citations:
......
cmake_minimum_required(VERSION 3.10)
project(doc NONE)
add_custom_target(doc)
# -- list all .tex source files ------------------------------------------------
set(sources
tex/Actors.tex
tex/Brokers.tex
tex/CommonPitfalls.tex
tex/ConfiguringActorApplications.tex
tex/Error.tex
tex/FAQ.tex
tex/FirstSteps.tex
tex/GroupCommunication.tex
tex/Introduction.tex
tex/ManagingGroupsOfWorkers.tex
tex/MessageHandlers.tex
tex/MessagePassing.tex
tex/Messages.tex
tex/MigrationGuides.tex
tex/NetworkTransparency.tex
tex/OpenCL.tex
tex/ReferenceCounting.tex
tex/Registry.tex
tex/RemoteSpawn.tex
tex/Scheduler.tex
tex/Streaming.tex
tex/TypeInspection.tex
tex/UsingAout.tex
tex/Utility.tex
)
# -- process .in files -----------------------------------------------------
configure_file("cmake/Doxyfile.in"
"${CMAKE_CURRENT_BINARY_DIR}/Doxyfile"
@ONLY)
file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/tex")
configure_file("cmake/variables.tex.in"
"${CMAKE_CURRENT_BINARY_DIR}/tex/variables.tex"
@ONLY)
file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/rst")
configure_file("cmake/conf.py.in"
"${CMAKE_CURRENT_BINARY_DIR}/rst/conf.py"
@ONLY)
configure_file("cmake/index_footer.rst.in"
"${CMAKE_CURRENT_BINARY_DIR}/rst/index_footer.rst"
@ONLY)
configure_file("cmake/index_header.rst.in"
"${CMAKE_CURRENT_BINARY_DIR}/rst/index_header.rst"
@ONLY)
# -- Doxygen setup -------------------------------------------------------------
find_package(Doxygen)
if(NOT DOXYGEN_FOUND)
message(STATUS "Doxygen not found, skip building API documentation.")
else()
message(STATUS "Add optional target: doxygen.")
add_custom_target(doxygen "${DOXYGEN_EXECUTABLE}"
"${CMAKE_CURRENT_BINARY_DIR}/Doxyfile"
WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}"
COMMENT "Generating API documentation with Doxygen"
VERBATIM)
add_dependencies(doc doxygen)
endif()
# -- Pandoc utility macro ------------------------------------------------------
macro(generate_rst texfile)
get_filename_component(rstfile_we "${texfile}" NAME_WE)
set(rstfile "${rstfile_we}.rst")
set(bin_texfile "${CMAKE_CURRENT_BINARY_DIR}/${texfile}")
add_custom_target("${rstfile}"
DEPENDS "${bin_texfile}"
COMMAND ${PANDOC_EXECUTABLE}
"--filter=${CMAKE_SOURCE_DIR}/scripts/pandoc-filter.py"
--wrap=none -f latex
-o "${CMAKE_CURRENT_BINARY_DIR}/rst/${rstfile}"
"${bin_texfile}"
WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/rst")
add_dependencies(rst "${rstfile}")
endmacro()
# -- LaTeX setup ---------------------------------------------------------------
find_package(LATEX QUIET)
if(NOT LATEX_FOUND)
message(STATUS "LaTeX not found, skip building manual.")
else()
message(STATUS "Add optional target: manual.")
include("cmake/UseLATEX.cmake")
# enable synctex for convenient editing
set(LATEX_USE_SYNCTEX yes)
# add manual.pdf as target
add_latex_document(tex/manual.tex
INPUTS ${sources} "tex/variables.tex"
IMAGE_DIRS "pdf"
FORCE_PDF
TARGET_NAME manual)
add_dependencies(doc manual)
find_program(PANDOC_EXECUTABLE pandoc)
if(NOT EXISTS ${PANDOC_EXECUTABLE})
message(STATUS "Pandoc not found, skip generating reFormattedText version of the manual.")
else()
execute_process(COMMAND "python" "-c"
"from pandocfilters import toJSONFilter; print('ok')"
RESULT_VARIABLE has_pandocfilters
OUTPUT_QUIET
ERROR_QUIET)
if(NOT ${has_pandocfilters} EQUAL 0)
message(STATUS "Python with pandocfilters not found, skip generating reFormattedText version of the manual.")
else()
message(STATUS "Add optional target: rst.")
add_custom_target(rst)
add_dependencies(doc rst)
foreach(texfile ${sources})
generate_rst(${texfile})
endforeach()
endif()
endif()
endif()
...@@ -20,261 +20,261 @@ MARKDOWN_SUPPORT = YES ...@@ -20,261 +20,261 @@ MARKDOWN_SUPPORT = YES
# Project related actor_system& system, const uration options # Project related actor_system& system, const uration options
#--------------------------------------------------------------------------- #---------------------------------------------------------------------------
# This tag specifies the encoding used for all characters in the actor_system& system, const file # This tag specifies the encoding used for all characters in the actor_system& system, const file
# that follow. The default is UTF-8 which is also the encoding used for all # that follow. The default is UTF-8 which is also the encoding used for all
# text before the first occurrence of this tag. Doxygen uses libiconv (or the # text before the first occurrence of this tag. Doxygen uses libiconv (or the
# iconv built into libc) for the transcoding. See # iconv built into libc) for the transcoding. See
# http://www.gnu.org/software/libiconv for the list of possible encodings. # http://www.gnu.org/software/libiconv for the list of possible encodings.
DOXYFILE_ENCODING = UTF-8 DOXYFILE_ENCODING = UTF-8
# The PROJECT_NAME tag is a single word (or a sequence of words surrounded # The PROJECT_NAME tag is a single word (or a sequence of words surrounded
# by quotes) that should identify the project. # by quotes) that should identify the project.
PROJECT_NAME = libcaf PROJECT_NAME = libcaf
# The PROJECT_NUMBER tag can be used to enter a project or revision number. # The PROJECT_NUMBER tag can be used to enter a project or revision number.
# This could be handy for archiving the generated documentation or # This could be handy for archiving the generated documentation or
# if some version control system is used. # if some version control system is used.
PROJECT_NUMBER = @CAF_VERSION@ PROJECT_NUMBER = @CAF_VERSION@
# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
# base path where the generated documentation will be put. # base path where the generated documentation will be put.
# If a relative path is entered, it will be relative to the location # If a relative path is entered, it will be relative to the location
# where doxygen was started. If left blank the current directory will be used. # where doxygen was started. If left blank the current directory will be used.
OUTPUT_DIRECTORY = OUTPUT_DIRECTORY =
# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create # If the CREATE_SUBDIRS tag is set to YES, then doxygen will create
# 4096 sub-directories (in 2 levels) under the output directory of each output # 4096 sub-directories (in 2 levels) under the output directory of each output
# format and will distribute the generated files over these directories. # format and will distribute the generated files over these directories.
# Enabling this option can be useful when feeding doxygen a huge amount of # Enabling this option can be useful when feeding doxygen a huge amount of
# source files, where putting all generated files in the same directory would # source files, where putting all generated files in the same directory would
# otherwise cause performance problems for the file system. # otherwise cause performance problems for the file system.
CREATE_SUBDIRS = NO CREATE_SUBDIRS = NO
# The OUTPUT_LANGUAGE tag is used to specify the language in which all # The OUTPUT_LANGUAGE tag is used to specify the language in which all
# documentation generated by doxygen is written. Doxygen will use this # documentation generated by doxygen is written. Doxygen will use this
# information to generate all constant output in the proper language. # information to generate all constant output in the proper language.
# The default language is English, other supported languages are: # The default language is English, other supported languages are:
# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, # Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional,
# Croatian, Czech, Danish, Dutch, Farsi, Finnish, French, German, Greek, # Croatian, Czech, Danish, Dutch, Farsi, Finnish, French, German, Greek,
# Hungarian, Italian, Japanese, Japanese-en (Japanese with English messages), # Hungarian, Italian, Japanese, Japanese-en (Japanese with English messages),
# Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, Polish, # Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, Polish,
# Portuguese, Romanian, Russian, Serbian, Serbian-Cyrilic, Slovak, Slovene, # Portuguese, Romanian, Russian, Serbian, Serbian-Cyrilic, Slovak, Slovene,
# Spanish, Swedish, and Ukrainian. # Spanish, Swedish, and Ukrainian.
OUTPUT_LANGUAGE = English OUTPUT_LANGUAGE = English
# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will # If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will
# include brief member descriptions after the members that are listed in # include brief member descriptions after the members that are listed in
# the file and class documentation (similar to JavaDoc). # the file and class documentation (similar to JavaDoc).
# Set to NO to disable this. # Set to NO to disable this.
BRIEF_MEMBER_DESC = YES BRIEF_MEMBER_DESC = YES
# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend # If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend
# the brief description of a member or function before the detailed description. # the brief description of a member or function before the detailed description.
# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the # Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
# brief descriptions will be completely suppressed. # brief descriptions will be completely suppressed.
REPEAT_BRIEF = YES REPEAT_BRIEF = YES
# This tag implements a quasi-intelligent brief description abbreviator # This tag implements a quasi-intelligent brief description abbreviator
# that is used to form the text in various listings. Each string # that is used to form the text in various listings. Each string
# in this list, if found as the leading text of the brief description, will be # in this list, if found as the leading text of the brief description, will be
# stripped from the text and the result after processing the whole list, is # stripped from the text and the result after processing the whole list, is
# used as the annotated text. Otherwise, the brief description is used as-is. # used as the annotated text. Otherwise, the brief description is used as-is.
# If left blank, the following values are used ("$name" is automatically # If left blank, the following values are used ("$name" is automatically
# replaced with the name of the entity): "The $name class" "The $name widget" # replaced with the name of the entity): "The $name class" "The $name widget"
# "The $name file" "is" "provides" "specifies" "contains" # "The $name file" "is" "provides" "specifies" "contains"
# "represents" "a" "an" "the" # "represents" "a" "an" "the"
ABBREVIATE_BRIEF = ABBREVIATE_BRIEF =
# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then # If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
# Doxygen will generate a detailed section even if there is only a brief # Doxygen will generate a detailed section even if there is only a brief
# description. # description.
ALWAYS_DETAILED_SEC = NO ALWAYS_DETAILED_SEC = NO
# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all # If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
# inherited members of a class in the documentation of that class as if those # inherited members of a class in the documentation of that class as if those
# members were ordinary class members. Constructors, destructors and assignment # members were ordinary class members. Constructors, destructors and assignment
# operators of the base classes will not be shown. # operators of the base classes will not be shown.
INLINE_INHERITED_MEMB = NO INLINE_INHERITED_MEMB = NO
# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full # If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full
# path before files name in the file list and in the header files. If set # path before files name in the file list and in the header files. If set
# to NO the shortest path that makes the file name unique will be used. # to NO the shortest path that makes the file name unique will be used.
FULL_PATH_NAMES = YES FULL_PATH_NAMES = YES
# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag # If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag
# can be used to strip a user-defined part of the path. Stripping is # can be used to strip a user-defined part of the path. Stripping is
# only done if one of the specified strings matches the left-hand part of # only done if one of the specified strings matches the left-hand part of
# the path. The tag can be used to show relative paths in the file list. # the path. The tag can be used to show relative paths in the file list.
# If left blank the directory from which doxygen is run is used as the # If left blank the directory from which doxygen is run is used as the
# path to strip. # path to strip.
STRIP_FROM_PATH = STRIP_FROM_PATH =
# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of # The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of
# the path mentioned in the documentation of a class, which tells # the path mentioned in the documentation of a class, which tells
# the reader which header file to include in order to use a class. # the reader which header file to include in order to use a class.
# If left blank only the name of the header file containing the class # If left blank only the name of the header file containing the class
# definition is used. Otherwise one should specify the include paths that # definition is used. Otherwise one should specify the include paths that
# are normally passed to the compiler using the -I flag. # are normally passed to the compiler using the -I flag.
STRIP_FROM_INC_PATH = STRIP_FROM_INC_PATH =
# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter # If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter
# (but less readable) file names. This can be useful is your file systems # (but less readable) file names. This can be useful is your file systems
# doesn't support long names like on DOS, Mac, or CD-ROM. # doesn't support long names like on DOS, Mac, or CD-ROM.
SHORT_NAMES = NO SHORT_NAMES = NO
# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen # If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen
# will interpret the first line (until the first dot) of a JavaDoc-style # will interpret the first line (until the first dot) of a JavaDoc-style
# comment as the brief description. If set to NO, the JavaDoc # comment as the brief description. If set to NO, the JavaDoc
# comments will behave just like regular Qt-style comments # comments will behave just like regular Qt-style comments
# (thus requiring an explicit @brief command for a brief description.) # (thus requiring an explicit @brief command for a brief description.)
JAVADOC_AUTOBRIEF = YES JAVADOC_AUTOBRIEF = YES
# If the QT_AUTOBRIEF tag is set to YES then Doxygen will # If the QT_AUTOBRIEF tag is set to YES then Doxygen will
# interpret the first line (until the first dot) of a Qt-style # interpret the first line (until the first dot) of a Qt-style
# comment as the brief description. If set to NO, the comments # comment as the brief description. If set to NO, the comments
# will behave just like regular Qt-style comments (thus requiring # will behave just like regular Qt-style comments (thus requiring
# an explicit \brief command for a brief description.) # an explicit \brief command for a brief description.)
QT_AUTOBRIEF = NO QT_AUTOBRIEF = NO
# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen # The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen
# treat a multi-line C++ special comment block (i.e. a block of //! or /// # treat a multi-line C++ special comment block (i.e. a block of //! or ///
# comments) as a brief description. This used to be the default behaviour. # comments) as a brief description. This used to be the default behaviour.
# The new default is to treat a multi-line C++ comment block as a detailed # The new default is to treat a multi-line C++ comment block as a detailed
# description. Set this tag to YES if you prefer the old behaviour instead. # description. Set this tag to YES if you prefer the old behaviour instead.
MULTILINE_CPP_IS_BRIEF = NO MULTILINE_CPP_IS_BRIEF = NO
# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented # If the INHERIT_DOCS tag is set to YES (the default) then an undocumented
# member inherits the documentation from any documented member that it # member inherits the documentation from any documented member that it
# re-implements. # re-implements.
INHERIT_DOCS = YES INHERIT_DOCS = YES
# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce # If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce
# a new page for each member. If set to NO, the documentation of a member will # a new page for each member. If set to NO, the documentation of a member will
# be part of the file/class/namespace that contains it. # be part of the file/class/namespace that contains it.
SEPARATE_MEMBER_PAGES = NO SEPARATE_MEMBER_PAGES = NO
# The TAB_SIZE tag can be used to set the number of spaces in a tab. # The TAB_SIZE tag can be used to set the number of spaces in a tab.
# Doxygen uses this value to replace tabs by spaces in code fragments. # Doxygen uses this value to replace tabs by spaces in code fragments.
TAB_SIZE = 2 TAB_SIZE = 2
# This tag can be used to specify a number of aliases that acts # This tag can be used to specify a number of aliases that acts
# as commands in the documentation. An alias has the form "name=value". # as commands in the documentation. An alias has the form "name=value".
# For example adding "sideeffect=\par Side Effects:\n" will allow you to # For example adding "sideeffect=\par Side Effects:\n" will allow you to
# put the command \sideeffect (or @sideeffect) in the documentation, which # put the command \sideeffect (or @sideeffect) in the documentation, which
# will result in a user-defined paragraph with heading "Side Effects:". # will result in a user-defined paragraph with heading "Side Effects:".
# You can put \n's in the value part of an alias to insert newlines. # You can put \n's in the value part of an alias to insert newlines.
ALIASES = experimental="@attention This feature is **experimental**." ALIASES = experimental="@attention This feature is **experimental**."
# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C # Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C
# sources only. Doxygen will then generate output that is more tailored for C. # sources only. Doxygen will then generate output that is more tailored for C.
# For instance, some of the names that are used will be different. The list # For instance, some of the names that are used will be different. The list
# of all members will be omitted, etc. # of all members will be omitted, etc.
OPTIMIZE_OUTPUT_FOR_C = NO OPTIMIZE_OUTPUT_FOR_C = NO
# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java # Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java
# sources only. Doxygen will then generate output that is more tailored for # sources only. Doxygen will then generate output that is more tailored for
# Java. For instance, namespaces will be presented as packages, qualified # Java. For instance, namespaces will be presented as packages, qualified
# scopes will look different, etc. # scopes will look different, etc.
OPTIMIZE_OUTPUT_JAVA = NO OPTIMIZE_OUTPUT_JAVA = NO
# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran # Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
# sources only. Doxygen will then generate output that is more tailored for # sources only. Doxygen will then generate output that is more tailored for
# Fortran. # Fortran.
OPTIMIZE_FOR_FORTRAN = NO OPTIMIZE_FOR_FORTRAN = NO
# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL # Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
# sources. Doxygen will then generate output that is tailored for # sources. Doxygen will then generate output that is tailored for
# VHDL. # VHDL.
OPTIMIZE_OUTPUT_VHDL = NO OPTIMIZE_OUTPUT_VHDL = NO
# Doxygen selects the parser to use depending on the extension of the files it parses. # Doxygen selects the parser to use depending on the extension of the files it parses.
# With this tag you can assign which parser to use for a given extension. # With this tag you can assign which parser to use for a given extension.
# Doxygen has a built-in mapping, but you can override or extend it using this tag. # Doxygen has a built-in mapping, but you can override or extend it using this tag.
# The format is ext=language, where ext is a file extension, and language is one of # The format is ext=language, where ext is a file extension, and language is one of
# the parsers supported by doxygen: IDL, Java, Javascript, C#, C, C++, D, PHP, # the parsers supported by doxygen: IDL, Java, Javascript, C#, C, C++, D, PHP,
# Objective-C, Python, Fortran, VHDL, C, C++. For instance to make doxygen treat # Objective-C, Python, Fortran, VHDL, C, C++. For instance to make doxygen treat
# .inc files as Fortran files (default is PHP), and .f files as C (default is Fortran), # .inc files as Fortran files (default is PHP), and .f files as C (default is Fortran),
# use: inc=Fortran f=C # use: inc=Fortran f=C
EXTENSION_MAPPING = C++ EXTENSION_MAPPING = C++
# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want # If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
# to include (a tag file for) the STL sources as input, then you should # to include (a tag file for) the STL sources as input, then you should
# set this tag to YES in order to let doxygen match functions declarations and # set this tag to YES in order to let doxygen match functions declarations and
# definitions whose arguments contain STL classes (e.g. func(std::string); v.s. # definitions whose arguments contain STL classes (e.g. func(std::string); v.s.
# func(std::string) {}). This also make the inheritance and collaboration # func(std::string) {}). This also make the inheritance and collaboration
# diagrams that involve STL classes more complete and accurate. # diagrams that involve STL classes more complete and accurate.
BUILTIN_STL_SUPPORT = YES BUILTIN_STL_SUPPORT = YES
# If you use Microsoft's C++/CLI language, you should set this option to YES to # If you use Microsoft's C++/CLI language, you should set this option to YES to
# enable parsing support. # enable parsing support.
CPP_CLI_SUPPORT = NO CPP_CLI_SUPPORT = NO
# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. # Set the SIP_SUPPORT tag to YES if your project consists of sip sources only.
# Doxygen will parse them like normal C++ but will assume all classes use public # Doxygen will parse them like normal C++ but will assume all classes use public
# instead of private inheritance when no explicit protection keyword is present. # instead of private inheritance when no explicit protection keyword is present.
SIP_SUPPORT = NO SIP_SUPPORT = NO
# For Microsoft's IDL there are propget and propput attributes to indicate getter # For Microsoft's IDL there are propget and propput attributes to indicate getter
# and setter methods for a property. Setting this option to YES (the default) # and setter methods for a property. Setting this option to YES (the default)
# will make doxygen to replace the get and set methods by a property in the # will make doxygen to replace the get and set methods by a property in the
# documentation. This will only work if the methods are indeed getting or # documentation. This will only work if the methods are indeed getting or
# setting a simple type. If this is not the case, or you want to show the # setting a simple type. If this is not the case, or you want to show the
# methods anyway, you should set this option to NO. # methods anyway, you should set this option to NO.
IDL_PROPERTY_SUPPORT = NO IDL_PROPERTY_SUPPORT = NO
# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC # If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
# tag is set to YES, then doxygen will reuse the documentation of the first # tag is set to YES, then doxygen will reuse the documentation of the first
# member in the group (if any) for the other members of the group. By default # member in the group (if any) for the other members of the group. By default
# all members of a group must be documented explicitly. # all members of a group must be documented explicitly.
DISTRIBUTE_GROUP_DOC = NO DISTRIBUTE_GROUP_DOC = NO
# Set the SUBGROUPING tag to YES (the default) to allow class member groups of # Set the SUBGROUPING tag to YES (the default) to allow class member groups of
# the same type (for instance a group of public functions) to be put as a # the same type (for instance a group of public functions) to be put as a
# subgroup of that type (e.g. under the Public Functions section). Set it to # subgroup of that type (e.g. under the Public Functions section). Set it to
# NO to prevent subgrouping. Alternatively, this can be done per class using # NO to prevent subgrouping. Alternatively, this can be done per class using
# the \nosubgrouping command. # the \nosubgrouping command.
SUBGROUPING = YES SUBGROUPING = YES
# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum # When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum
# is documented as struct, union, or enum with the name of the typedef. So # is documented as struct, union, or enum with the name of the typedef. So
# typedef struct TypeS {} TypeT, will appear in the documentation as a struct # typedef struct TypeS {} TypeT, will appear in the documentation as a struct
# with name TypeT. When disabled the typedef will appear as a member of a file, # with name TypeT. When disabled the typedef will appear as a member of a file,
# namespace, or class. And the struct will be named TypeS. This can typically # namespace, or class. And the struct will be named TypeS. This can typically
# be useful for C code in case the coding convention dictates that all compound # be useful for C code in case the coding convention dictates that all compound
# types are typedef'ed and only the typedef is referenced, never the tag name. # types are typedef'ed and only the typedef is referenced, never the tag name.
TYPEDEF_HIDES_STRUCT = NO TYPEDEF_HIDES_STRUCT = NO
...@@ -283,270 +283,270 @@ TYPEDEF_HIDES_STRUCT = NO ...@@ -283,270 +283,270 @@ TYPEDEF_HIDES_STRUCT = NO
# Build related actor_system& system, const uration options # Build related actor_system& system, const uration options
#--------------------------------------------------------------------------- #---------------------------------------------------------------------------
# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in # If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
# documentation are documented, even if no documentation was available. # documentation are documented, even if no documentation was available.
# Private class members and static file members will be hidden unless # Private class members and static file members will be hidden unless
# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES # the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
EXTRACT_ALL = NO EXTRACT_ALL = NO
# If the EXTRACT_PRIVATE tag is set to YES all private members of a class # If the EXTRACT_PRIVATE tag is set to YES all private members of a class
# will be included in the documentation. # will be included in the documentation.
EXTRACT_PRIVATE = NO EXTRACT_PRIVATE = NO
# If the EXTRACT_STATIC tag is set to YES all static members of a file # If the EXTRACT_STATIC tag is set to YES all static members of a file
# will be included in the documentation. # will be included in the documentation.
EXTRACT_STATIC = YES EXTRACT_STATIC = YES
# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) # If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs)
# defined locally in source files will be included in the documentation. # defined locally in source files will be included in the documentation.
# If set to NO only classes defined in header files are included. # If set to NO only classes defined in header files are included.
EXTRACT_LOCAL_CLASSES = YES EXTRACT_LOCAL_CLASSES = YES
# This flag is only useful for Objective-C code. When set to YES local # This flag is only useful for Objective-C code. When set to YES local
# methods, which are defined in the implementation section but not in # methods, which are defined in the implementation section but not in
# the interface are included in the documentation. # the interface are included in the documentation.
# If set to NO (the default) only methods in the interface are included. # If set to NO (the default) only methods in the interface are included.
EXTRACT_LOCAL_METHODS = NO EXTRACT_LOCAL_METHODS = NO
# If this flag is set to YES, the members of anonymous namespaces will be # If this flag is set to YES, the members of anonymous namespaces will be
# extracted and appear in the documentation as a namespace called # extracted and appear in the documentation as a namespace called
# 'anonymous_namespace{file}', where file will be replaced with the base # 'anonymous_namespace{file}', where file will be replaced with the base
# name of the file that contains the anonymous namespace. By default # name of the file that contains the anonymous namespace. By default
# anonymous namespace are hidden. # anonymous namespace are hidden.
EXTRACT_ANON_NSPACES = NO EXTRACT_ANON_NSPACES = NO
# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all # If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all
# undocumented members of documented classes, files or namespaces. # undocumented members of documented classes, files or namespaces.
# If set to NO (the default) these members will be included in the # If set to NO (the default) these members will be included in the
# various overviews, but no documentation section is generated. # various overviews, but no documentation section is generated.
# This option has no effect if EXTRACT_ALL is enabled. # This option has no effect if EXTRACT_ALL is enabled.
HIDE_UNDOC_MEMBERS = NO HIDE_UNDOC_MEMBERS = NO
# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all # If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all
# undocumented classes that are normally visible in the class hierarchy. # undocumented classes that are normally visible in the class hierarchy.
# If set to NO (the default) these classes will be included in the various # If set to NO (the default) these classes will be included in the various
# overviews. This option has no effect if EXTRACT_ALL is enabled. # overviews. This option has no effect if EXTRACT_ALL is enabled.
HIDE_UNDOC_CLASSES = YES HIDE_UNDOC_CLASSES = YES
# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all # If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all
# friend (class|struct|union) declarations. # friend (class|struct|union) declarations.
# If set to NO (the default) these declarations will be included in the # If set to NO (the default) these declarations will be included in the
# documentation. # documentation.
HIDE_FRIEND_COMPOUNDS = NO HIDE_FRIEND_COMPOUNDS = NO
# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any # If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any
# documentation blocks found inside the body of a function. # documentation blocks found inside the body of a function.
# If set to NO (the default) these blocks will be appended to the # If set to NO (the default) these blocks will be appended to the
# function's detailed documentation block. # function's detailed documentation block.
HIDE_IN_BODY_DOCS = NO HIDE_IN_BODY_DOCS = NO
# The INTERNAL_DOCS tag determines if documentation # The INTERNAL_DOCS tag determines if documentation
# that is typed after a \internal command is included. If the tag is set # that is typed after a \internal command is included. If the tag is set
# to NO (the default) then the documentation will be excluded. # to NO (the default) then the documentation will be excluded.
# Set it to YES to include the internal documentation. # Set it to YES to include the internal documentation.
INTERNAL_DOCS = NO INTERNAL_DOCS = NO
# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate # If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate
# file names in lower-case letters. If set to YES upper-case letters are also # file names in lower-case letters. If set to YES upper-case letters are also
# allowed. This is useful if you have classes or files whose names only differ # allowed. This is useful if you have classes or files whose names only differ
# in case and if your file system supports case sensitive file names. Windows # in case and if your file system supports case sensitive file names. Windows
# and Mac users are advised to set this option to NO. # and Mac users are advised to set this option to NO.
CASE_SENSE_NAMES = NO CASE_SENSE_NAMES = NO
# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen # If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen
# will show members with their full class and namespace scopes in the # will show members with their full class and namespace scopes in the
# documentation. If set to YES the scope will be hidden. # documentation. If set to YES the scope will be hidden.
HIDE_SCOPE_NAMES = NO HIDE_SCOPE_NAMES = NO
# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen # If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen
# will put a list of the files that are included by a file in the documentation # will put a list of the files that are included by a file in the documentation
# of that file. # of that file.
SHOW_INCLUDE_FILES = YES SHOW_INCLUDE_FILES = YES
# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] # If the INLINE_INFO tag is set to YES (the default) then a tag [inline]
# is inserted in the documentation for inline members. # is inserted in the documentation for inline members.
INLINE_INFO = NO INLINE_INFO = NO
# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen # If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen
# will sort the (detailed) documentation of file and class members # will sort the (detailed) documentation of file and class members
# alphabetically by member name. If set to NO the members will appear in # alphabetically by member name. If set to NO the members will appear in
# declaration order. # declaration order.
SORT_MEMBER_DOCS = YES SORT_MEMBER_DOCS = YES
# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the # If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the
# brief documentation of file, namespace and class members alphabetically # brief documentation of file, namespace and class members alphabetically
# by member name. If set to NO (the default) the members will appear in # by member name. If set to NO (the default) the members will appear in
# declaration order. # declaration order.
SORT_BRIEF_DOCS = NO SORT_BRIEF_DOCS = NO
# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the # If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the
# hierarchy of group names into alphabetical order. If set to NO (the default) # hierarchy of group names into alphabetical order. If set to NO (the default)
# the group names will appear in their defined order. # the group names will appear in their defined order.
SORT_GROUP_NAMES = YES SORT_GROUP_NAMES = YES
# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be # If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be
# sorted by fully-qualified names, including namespaces. If set to # sorted by fully-qualified names, including namespaces. If set to
# NO (the default), the class list will be sorted only by class name, # NO (the default), the class list will be sorted only by class name,
# not including the namespace part. # not including the namespace part.
# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. # Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
# Note: This option applies only to the class list, not to the # Note: This option applies only to the class list, not to the
# alphabetical list. # alphabetical list.
SORT_BY_SCOPE_NAME = YES SORT_BY_SCOPE_NAME = YES
# The GENERATE_TODOLIST tag can be used to enable (YES) or # The GENERATE_TODOLIST tag can be used to enable (YES) or
# disable (NO) the todo list. This list is created by putting \todo # disable (NO) the todo list. This list is created by putting \todo
# commands in the documentation. # commands in the documentation.
GENERATE_TODOLIST = NO GENERATE_TODOLIST = NO
# The GENERATE_TESTLIST tag can be used to enable (YES) or # The GENERATE_TESTLIST tag can be used to enable (YES) or
# disable (NO) the test list. This list is created by putting \test # disable (NO) the test list. This list is created by putting \test
# commands in the documentation. # commands in the documentation.
GENERATE_TESTLIST = YES GENERATE_TESTLIST = YES
# The GENERATE_BUGLIST tag can be used to enable (YES) or # The GENERATE_BUGLIST tag can be used to enable (YES) or
# disable (NO) the bug list. This list is created by putting \bug # disable (NO) the bug list. This list is created by putting \bug
# commands in the documentation. # commands in the documentation.
GENERATE_BUGLIST = YES GENERATE_BUGLIST = YES
# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or # The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or
# disable (NO) the deprecated list. This list is created by putting # disable (NO) the deprecated list. This list is created by putting
# \deprecated commands in the documentation. # \deprecated commands in the documentation.
GENERATE_DEPRECATEDLIST= YES GENERATE_DEPRECATEDLIST= YES
# The ENABLED_SECTIONS tag can be used to enable conditional # The ENABLED_SECTIONS tag can be used to enable conditional
# documentation sections, marked by \if sectionname ... \endif. # documentation sections, marked by \if sectionname ... \endif.
ENABLED_SECTIONS = ENABLED_SECTIONS =
# The MAX_INITIALIZER_LINES tag determines the maximum number of lines # The MAX_INITIALIZER_LINES tag determines the maximum number of lines
# the initial value of a variable or define consists of for it to appear in # the initial value of a variable or define consists of for it to appear in
# the documentation. If the initializer consists of more lines than specified # the documentation. If the initializer consists of more lines than specified
# here it will be hidden. Use a value of 0 to hide initializers completely. # here it will be hidden. Use a value of 0 to hide initializers completely.
# The appearance of the initializer of individual variables and defines in the # The appearance of the initializer of individual variables and defines in the
# documentation can be controlled using \showinitializer or \hideinitializer # documentation can be controlled using \showinitializer or \hideinitializer
# command in the documentation regardless of this setting. # command in the documentation regardless of this setting.
MAX_INITIALIZER_LINES = 30 MAX_INITIALIZER_LINES = 30
# Set the SHOW_USED_FILES tag to NO to disable the list of files generated # Set the SHOW_USED_FILES tag to NO to disable the list of files generated
# at the bottom of the documentation of classes and structs. If set to YES the # at the bottom of the documentation of classes and structs. If set to YES the
# list will mention the files that were used to generate the documentation. # list will mention the files that were used to generate the documentation.
SHOW_USED_FILES = YES SHOW_USED_FILES = YES
# Set the SHOW_FILES tag to NO to disable the generation of the Files page. # Set the SHOW_FILES tag to NO to disable the generation of the Files page.
# This will remove the Files entry from the Quick Index and from the # This will remove the Files entry from the Quick Index and from the
# Folder Tree View (if specified). The default is YES. # Folder Tree View (if specified). The default is YES.
SHOW_FILES = YES SHOW_FILES = YES
# Set the SHOW_NAMESPACES tag to NO to disable the generation of the # Set the SHOW_NAMESPACES tag to NO to disable the generation of the
# Namespaces page. # Namespaces page.
# This will remove the Namespaces entry from the Quick Index # This will remove the Namespaces entry from the Quick Index
# and from the Folder Tree View (if specified). The default is YES. # and from the Folder Tree View (if specified). The default is YES.
SHOW_NAMESPACES = YES SHOW_NAMESPACES = YES
# The FILE_VERSION_FILTER tag can be used to specify a program or script that # The FILE_VERSION_FILTER tag can be used to specify a program or script that
# doxygen should invoke to get the current version for each file (typically from # doxygen should invoke to get the current version for each file (typically from
# the version control system). Doxygen will invoke the program by executing (via # the version control system). Doxygen will invoke the program by executing (via
# popen()) the command <command> <input-file>, where <command> is the value of # popen()) the command <command> <input-file>, where <command> is the value of
# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file # the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file
# provided by doxygen. Whatever the program writes to standard output # provided by doxygen. Whatever the program writes to standard output
# is used as the file version. See the manual for examples. # is used as the file version. See the manual for examples.
FILE_VERSION_FILTER = FILE_VERSION_FILTER =
# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed by # The LAYOUT_FILE tag can be used to specify a layout file which will be parsed by
# doxygen. The layout file controls the global structure of the generated output files # doxygen. The layout file controls the global structure of the generated output files
# in an output format independent way. The create the layout file that represents # in an output format independent way. The create the layout file that represents
# doxygen's defaults, run doxygen with the -l option. You can optionally specify a # doxygen's defaults, run doxygen with the -l option. You can optionally specify a
# file name after the option, if omitted DoxygenLayout.xml will be used as the name # file name after the option, if omitted DoxygenLayout.xml will be used as the name
# of the layout file. # of the layout file.
LAYOUT_FILE = LAYOUT_FILE =
#--------------------------------------------------------------------------- #---------------------------------------------------------------------------
# actor_system& system, const uration options related to warning and progress messages # actor_system& system, const uration options related to warning and progress messages
#--------------------------------------------------------------------------- #---------------------------------------------------------------------------
# The QUIET tag can be used to turn on/off the messages that are generated # The QUIET tag can be used to turn on/off the messages that are generated
# by doxygen. Possible values are YES and NO. If left blank NO is used. # by doxygen. Possible values are YES and NO. If left blank NO is used.
QUIET = NO QUIET = NO
# The WARNINGS tag can be used to turn on/off the warning messages that are # The WARNINGS tag can be used to turn on/off the warning messages that are
# generated by doxygen. Possible values are YES and NO. If left blank # generated by doxygen. Possible values are YES and NO. If left blank
# NO is used. # NO is used.
WARNINGS = YES WARNINGS = YES
# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings # If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings
# for undocumented members. If EXTRACT_ALL is set to YES then this flag will # for undocumented members. If EXTRACT_ALL is set to YES then this flag will
# automatically be disabled. # automatically be disabled.
WARN_IF_UNDOCUMENTED = YES WARN_IF_UNDOCUMENTED = YES
# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for # If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for
# potential errors in the documentation, such as not documenting some # potential errors in the documentation, such as not documenting some
# parameters in a documented function, or documenting parameters that # parameters in a documented function, or documenting parameters that
# don't exist or using markup commands wrongly. # don't exist or using markup commands wrongly.
WARN_IF_DOC_ERROR = YES WARN_IF_DOC_ERROR = YES
# This WARN_NO_PARAMDOC option can be abled to get warnings for # This WARN_NO_PARAMDOC option can be abled to get warnings for
# functions that are documented, but have no documentation for their parameters # functions that are documented, but have no documentation for their parameters
# or return value. If set to NO (the default) doxygen will only warn about # or return value. If set to NO (the default) doxygen will only warn about
# wrong or incomplete parameter documentation, but not about the absence of # wrong or incomplete parameter documentation, but not about the absence of
# documentation. # documentation.
WARN_NO_PARAMDOC = YES WARN_NO_PARAMDOC = YES
# The WARN_FORMAT tag determines the format of the warning messages that # The WARN_FORMAT tag determines the format of the warning messages that
# doxygen can produce. The string should contain the $file, $line, and $text # doxygen can produce. The string should contain the $file, $line, and $text
# tags, which will be replaced by the file and line number from which the # tags, which will be replaced by the file and line number from which the
# warning originated and the warning text. Optionally the format may contain # warning originated and the warning text. Optionally the format may contain
# $version, which will be replaced by the version of the file (if it could # $version, which will be replaced by the version of the file (if it could
# be obtained via FILE_VERSION_FILTER) # be obtained via FILE_VERSION_FILTER)
WARN_FORMAT = "$file:$line: $text" WARN_FORMAT = "$file:$line: $text"
# The WARN_LOGFILE tag can be used to specify a file to which warning # The WARN_LOGFILE tag can be used to specify a file to which warning
# and error messages should be written. If left blank the output is written # and error messages should be written. If left blank the output is written
# to stderr. # to stderr.
WARN_LOGFILE = WARN_LOGFILE =
#--------------------------------------------------------------------------- #---------------------------------------------------------------------------
# actor_system& system, const uration options related to the input files # actor_system& system, const uration options related to the input files
#--------------------------------------------------------------------------- #---------------------------------------------------------------------------
# The INPUT tag can be used to specify the files and/or directories that contain # The INPUT tag can be used to specify the files and/or directories that contain
# documented source files. You may enter file names like "myfile.cpp" or # documented source files. You may enter file names like "myfile.cpp" or
# directories like "/usr/src/myproject". Separate the files or directories # directories like "/usr/src/myproject". Separate the files or directories
# with spaces. # with spaces.
INPUT = "@CMAKE_HOME_DIRECTORY@/libcaf_core/caf" \ INPUT = "@CMAKE_HOME_DIRECTORY@/libcaf_core/caf" \
...@@ -557,107 +557,107 @@ INPUT = "@CMAKE_HOME_DIRECTORY@/libcaf_core/caf" \ ...@@ -557,107 +557,107 @@ INPUT = "@CMAKE_HOME_DIRECTORY@/libcaf_core/caf" \
"@CMAKE_HOME_DIRECTORY@/libcaf_io/caf/io" \ "@CMAKE_HOME_DIRECTORY@/libcaf_io/caf/io" \
"@CMAKE_HOME_DIRECTORY@/libcaf_io/caf/io/network" "@CMAKE_HOME_DIRECTORY@/libcaf_io/caf/io/network"
# This tag can be used to specify the character encoding of the source files # This tag can be used to specify the character encoding of the source files
# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is # that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is
# also the default input encoding. Doxygen uses libiconv (or the iconv built # also the default input encoding. Doxygen uses libiconv (or the iconv built
# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for # into libc) for the transcoding. See http://www.gnu.org/software/libiconv for
# the list of possible encodings. # the list of possible encodings.
INPUT_ENCODING = UTF-8 INPUT_ENCODING = UTF-8
# If the value of the INPUT tag contains directories, you can use the # If the value of the INPUT tag contains directories, you can use the
# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp # FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
# and *.h) to filter out the source-files in the directories. If left # and *.h) to filter out the source-files in the directories. If left
# blank the following patterns are tested: # blank the following patterns are tested:
# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx # *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx
# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py *.f90 # *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py *.f90
FILE_PATTERNS = FILE_PATTERNS =
# The RECURSIVE tag can be used to turn specify whether or not subdirectories # The RECURSIVE tag can be used to turn specify whether or not subdirectories
# should be searched for input files as well. Possible values are YES and NO. # should be searched for input files as well. Possible values are YES and NO.
# If left blank NO is used. # If left blank NO is used.
RECURSIVE = NO RECURSIVE = NO
# The EXCLUDE tag can be used to specify files and/or directories that should # The EXCLUDE tag can be used to specify files and/or directories that should
# excluded from the INPUT source files. This way you can easily exclude a # excluded from the INPUT source files. This way you can easily exclude a
# subdirectory from a directory tree whose root is specified with the INPUT tag. # subdirectory from a directory tree whose root is specified with the INPUT tag.
EXCLUDE = EXCLUDE =
# The EXCLUDE_SYMLINKS tag can be used select whether or not files or # The EXCLUDE_SYMLINKS tag can be used select whether or not files or
# directories that are symbolic links (a Unix filesystem feature) are excluded # directories that are symbolic links (a Unix filesystem feature) are excluded
# from the input. # from the input.
EXCLUDE_SYMLINKS = NO EXCLUDE_SYMLINKS = NO
# If the value of the INPUT tag contains directories, you can use the # If the value of the INPUT tag contains directories, you can use the
# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude # EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
# certain files from those directories. Note that the wildcards are matched # certain files from those directories. Note that the wildcards are matched
# against the file with absolute path, so to exclude all test directories # against the file with absolute path, so to exclude all test directories
# for example use the pattern */test/* # for example use the pattern */test/*
EXCLUDE_PATTERNS = EXCLUDE_PATTERNS =
# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names # The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
# (namespaces, classes, functions, etc.) that should be excluded from the # (namespaces, classes, functions, etc.) that should be excluded from the
# output. The symbol name can be a fully qualified name, a word, or if the # output. The symbol name can be a fully qualified name, a word, or if the
# wildcard * is used, a substring. Examples: ANamespace, AClass, # wildcard * is used, a substring. Examples: ANamespace, AClass,
# AClass::ANamespace, ANamespace::*Test # AClass::ANamespace, ANamespace::*Test
EXCLUDE_SYMBOLS = EXCLUDE_SYMBOLS =
# The EXAMPLE_PATH tag can be used to specify one or more files or # The EXAMPLE_PATH tag can be used to specify one or more files or
# directories that contain example code fragments that are included (see # directories that contain example code fragments that are included (see
# the \include command). # the \include command).
EXAMPLE_PATH = examples EXAMPLE_PATH = examples
# If the value of the EXAMPLE_PATH tag contains directories, you can use the # If the value of the EXAMPLE_PATH tag contains directories, you can use the
# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp # EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
# and *.h) to filter out the source-files in the directories. If left # and *.h) to filter out the source-files in the directories. If left
# blank all files are included. # blank all files are included.
EXAMPLE_PATTERNS = EXAMPLE_PATTERNS =
# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be # If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
# searched for input files to be used with the \include or \dontinclude # searched for input files to be used with the \include or \dontinclude
# commands irrespective of the value of the RECURSIVE tag. # commands irrespective of the value of the RECURSIVE tag.
# Possible values are YES and NO. If left blank NO is used. # Possible values are YES and NO. If left blank NO is used.
EXAMPLE_RECURSIVE = YES EXAMPLE_RECURSIVE = YES
# The IMAGE_PATH tag can be used to specify one or more files or # The IMAGE_PATH tag can be used to specify one or more files or
# directories that contain image that are included in the documentation (see # directories that contain image that are included in the documentation (see
# the \image command). # the \image command).
IMAGE_PATH = @CMAKE_HOME_DIRECTORY@/doc/ IMAGE_PATH = "@CMAKE_HOME_DIRECTORY@/doc/png/"
# The INPUT_FILTER tag can be used to specify a program that doxygen should # The INPUT_FILTER tag can be used to specify a program that doxygen should
# invoke to filter for each input file. Doxygen will invoke the filter program # invoke to filter for each input file. Doxygen will invoke the filter program
# by executing (via popen()) the command <filter> <input-file>, where <filter> # by executing (via popen()) the command <filter> <input-file>, where <filter>
# is the value of the INPUT_FILTER tag, and <input-file> is the name of an # is the value of the INPUT_FILTER tag, and <input-file> is the name of an
# input file. Doxygen will then use the output that the filter program writes # input file. Doxygen will then use the output that the filter program writes
# to standard output. # to standard output.
# If FILTER_PATTERNS is specified, this tag will be # If FILTER_PATTERNS is specified, this tag will be
# ignored. # ignored.
INPUT_FILTER = INPUT_FILTER =
# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern # The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
# basis. # basis.
# Doxygen will compare the file name with each pattern and apply the # Doxygen will compare the file name with each pattern and apply the
# filter if there is a match. # filter if there is a match.
# The filters are a list of the form: # The filters are a list of the form:
# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further # pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further
# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER # info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER
# is applied to all files. # is applied to all files.
FILTER_PATTERNS = FILTER_PATTERNS =
# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using # If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
# INPUT_FILTER) will be used to filter the input files when producing source # INPUT_FILTER) will be used to filter the input files when producing source
# files to browse (i.e. when SOURCE_BROWSER is set to YES). # files to browse (i.e. when SOURCE_BROWSER is set to YES).
FILTER_SOURCE_FILES = NO FILTER_SOURCE_FILES = NO
...@@ -666,54 +666,54 @@ FILTER_SOURCE_FILES = NO ...@@ -666,54 +666,54 @@ FILTER_SOURCE_FILES = NO
# actor_system& system, const uration options related to source browsing # actor_system& system, const uration options related to source browsing
#--------------------------------------------------------------------------- #---------------------------------------------------------------------------
# If the SOURCE_BROWSER tag is set to YES then a list of source files will # If the SOURCE_BROWSER tag is set to YES then a list of source files will
# be generated. Documented entities will be cross-referenced with these sources. # be generated. Documented entities will be cross-referenced with these sources.
# Note: To get rid of all source code in the generated output, make sure also # Note: To get rid of all source code in the generated output, make sure also
# VERBATIM_HEADERS is set to NO. # VERBATIM_HEADERS is set to NO.
SOURCE_BROWSER = NO SOURCE_BROWSER = NO
# Setting the INLINE_SOURCES tag to YES will include the body # Setting the INLINE_SOURCES tag to YES will include the body
# of functions and classes directly in the documentation. # of functions and classes directly in the documentation.
INLINE_SOURCES = NO INLINE_SOURCES = NO
# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct # Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct
# doxygen to hide any special comment blocks from generated source code # doxygen to hide any special comment blocks from generated source code
# fragments. Normal C and C++ comments will always remain visible. # fragments. Normal C and C++ comments will always remain visible.
STRIP_CODE_COMMENTS = YES STRIP_CODE_COMMENTS = YES
# If the REFERENCED_BY_RELATION tag is set to YES # If the REFERENCED_BY_RELATION tag is set to YES
# then for each documented function all documented # then for each documented function all documented
# functions referencing it will be listed. # functions referencing it will be listed.
REFERENCED_BY_RELATION = NO REFERENCED_BY_RELATION = NO
# If the REFERENCES_RELATION tag is set to YES # If the REFERENCES_RELATION tag is set to YES
# then for each documented function all documented entities # then for each documented function all documented entities
# called/used by that function will be listed. # called/used by that function will be listed.
REFERENCES_RELATION = NO REFERENCES_RELATION = NO
# If the REFERENCES_LINK_SOURCE tag is set to YES (the default) # If the REFERENCES_LINK_SOURCE tag is set to YES (the default)
# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from # and SOURCE_BROWSER tag is set to YES, then the hyperlinks from
# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will # functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will
# link to the source code. # link to the source code.
# Otherwise they will link to the documentation. # Otherwise they will link to the documentation.
REFERENCES_LINK_SOURCE = YES REFERENCES_LINK_SOURCE = YES
# If the USE_HTAGS tag is set to YES then the references to source code # If the USE_HTAGS tag is set to YES then the references to source code
# will point to the HTML generated by the htags(1) tool instead of doxygen # will point to the HTML generated by the htags(1) tool instead of doxygen
# built-in source browser. The htags tool is part of GNU's global source # built-in source browser. The htags tool is part of GNU's global source
# tagging system (see http://www.gnu.org/software/global/global.html). You # tagging system (see http://www.gnu.org/software/global/global.html). You
# will need version 4.8.6 or higher. # will need version 4.8.6 or higher.
USE_HTAGS = NO USE_HTAGS = NO
# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen # If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen
# will generate a verbatim copy of the header file for each class for # will generate a verbatim copy of the header file for each class for
# which an include is specified. Set to NO to disable this. # which an include is specified. Set to NO to disable this.
VERBATIM_HEADERS = NO VERBATIM_HEADERS = NO
...@@ -722,742 +722,471 @@ VERBATIM_HEADERS = NO ...@@ -722,742 +722,471 @@ VERBATIM_HEADERS = NO
# actor_system& system, const uration options related to the alphabetical class index # actor_system& system, const uration options related to the alphabetical class index
#--------------------------------------------------------------------------- #---------------------------------------------------------------------------
# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index # If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index
# of all compounds will be generated. Enable this if the project # of all compounds will be generated. Enable this if the project
# contains a lot of classes, structs, unions or interfaces. # contains a lot of classes, structs, unions or interfaces.
ALPHABETICAL_INDEX = YES ALPHABETICAL_INDEX = YES
# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then # If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then
# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns # the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns
# in which this list will be split (can be a number in the range [1..20]) # in which this list will be split (can be a number in the range [1..20])
COLS_IN_ALPHA_INDEX = 5 COLS_IN_ALPHA_INDEX = 5
# In case all classes in a project start with a common prefix, all # In case all classes in a project start with a common prefix, all
# classes will be put under the same header in the alphabetical index. # classes will be put under the same header in the alphabetical index.
# The IGNORE_PREFIX tag can be used to specify one or more prefixes that # The IGNORE_PREFIX tag can be used to specify one or more prefixes that
# should be ignored while generating the index headers. # should be ignored while generating the index headers.
IGNORE_PREFIX = IGNORE_PREFIX =
#--------------------------------------------------------------------------- #---------------------------------------------------------------------------
# actor_system& system, const uration options related to the HTML output # actor_system& system, const uration options related to the HTML output
#--------------------------------------------------------------------------- #---------------------------------------------------------------------------
# If the GENERATE_HTML tag is set to YES (the default) Doxygen will # If the GENERATE_HTML tag is set to YES (the default) Doxygen will
# generate HTML output. # generate HTML output.
GENERATE_HTML = YES GENERATE_HTML = YES
# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. # The HTML_OUTPUT tag is used to specify where the HTML docs will be put.
# If a relative path is entered the value of OUTPUT_DIRECTORY will be # If a relative path is entered the value of OUTPUT_DIRECTORY will be
# put in front of it. If left blank `html' will be used as the default path. # put in front of it. If left blank `html' will be used as the default path.
HTML_OUTPUT = html HTML_OUTPUT = html
# The HTML_FILE_EXTENSION tag can be used to specify the file extension for # The HTML_FILE_EXTENSION tag can be used to specify the file extension for
# each generated HTML page (for example: .htm,.php,.asp). If it is left blank # each generated HTML page (for example: .htm,.php,.asp). If it is left blank
# doxygen will generate files with .html extension. # doxygen will generate files with .html extension.
HTML_FILE_EXTENSION = .html HTML_FILE_EXTENSION = .html
# The HTML_HEADER tag can be used to specify a personal HTML header for # The HTML_HEADER tag can be used to specify a personal HTML header for
# each generated HTML page. If it is left blank doxygen will generate a # each generated HTML page. If it is left blank doxygen will generate a
# standard header. # standard header.
HTML_HEADER = HTML_HEADER =
# The HTML_FOOTER tag can be used to specify a personal HTML footer for # The HTML_FOOTER tag can be used to specify a personal HTML footer for
# each generated HTML page. If it is left blank doxygen will generate a # each generated HTML page. If it is left blank doxygen will generate a
# standard footer. # standard footer.
HTML_FOOTER = HTML_FOOTER =
# The HTML_STYLESHEET tag can be used to specify a user-defined cascading # The HTML_STYLESHEET tag can be used to specify a user-defined cascading
# style sheet that is used by each HTML page. It can be used to # style sheet that is used by each HTML page. It can be used to
# fine-tune the look of the HTML output. If the tag is left blank doxygen # fine-tune the look of the HTML output. If the tag is left blank doxygen
# will generate a default style sheet. Note that doxygen will try to copy # will generate a default style sheet. Note that doxygen will try to copy
# the style sheet file to the HTML output directory, so don't put your own # the style sheet file to the HTML output directory, so don't put your own
# stylesheet in the HTML output directory as well, or it will be erased! # stylesheet in the HTML output directory as well, or it will be erased!
HTML_STYLESHEET = HTML_STYLESHEET =
# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML # If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
# documentation will contain sections that can be hidden and shown after the # documentation will contain sections that can be hidden and shown after the
# page has loaded. For this to work a browser that supports # page has loaded. For this to work a browser that supports
# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox # JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox
# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari). # Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari).
HTML_DYNAMIC_SECTIONS = NO HTML_DYNAMIC_SECTIONS = NO
# If the GENERATE_DOCSET tag is set to YES, additional index files # If the GENERATE_HTMLHELP tag is set to YES, additional index files
# will be generated that can be used as input for Apple's Xcode 3 # will be generated that can be used as input for tools like the
# integrated development environment, introduced with OSX 10.5 (Leopard). # Microsoft HTML help workshop to generate a compiled HTML help file (.chm)
# To create a documentation set, doxygen will generate a Makefile in the
# HTML output directory. Running make will produce the docset in that
# directory and running "make install" will install the docset in
# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find
# it at startup.
# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html for more information.
GENERATE_DOCSET = NO
# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the
# feed. A documentation feed provides an umbrella under which multiple
# documentation sets from a single provider (such as a company or product suite)
# can be grouped.
DOCSET_FEEDNAME = "Doxygen generated docs"
# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that
# should uniquely identify the documentation set bundle. This should be a
# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen
# will append .docset to the name.
DOCSET_BUNDLE_ID = org.doxygen.Project
# If the GENERATE_HTMLHELP tag is set to YES, additional index files
# will be generated that can be used as input for tools like the
# Microsoft HTML help workshop to generate a compiled HTML help file (.chm)
# of the generated HTML documentation. # of the generated HTML documentation.
GENERATE_HTMLHELP = NO GENERATE_HTMLHELP = NO
# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can # If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can
# be used to specify the file name of the resulting .chm file. You # be used to specify the file name of the resulting .chm file. You
# can add a path in front of the file if the result should not be # can add a path in front of the file if the result should not be
# written to the html output directory. # written to the html output directory.
CHM_FILE = CHM_FILE =
# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can # If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can
# be used to specify the location (absolute path including file name) of # be used to specify the location (absolute path including file name) of
# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run # the HTML help compiler (hhc.exe). If non-empty doxygen will try to run
# the HTML help compiler on the generated index.hhp. # the HTML help compiler on the generated index.hhp.
HHC_LOCATION = HHC_LOCATION =
# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag # If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag
# controls if a separate .chi index file is generated (YES) or that # controls if a separate .chi index file is generated (YES) or that
# it should be included in the master .chm file (NO). # it should be included in the master .chm file (NO).
GENERATE_CHI = NO GENERATE_CHI = NO
# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING # If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING
# is used to encode HtmlHelp index (hhk), content (hhc) and project file # is used to encode HtmlHelp index (hhk), content (hhc) and project file
# content. # content.
CHM_INDEX_ENCODING = CHM_INDEX_ENCODING =
# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag # If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag
# controls whether a binary table of contents is generated (YES) or a # controls whether a binary table of contents is generated (YES) or a
# normal table of contents (NO) in the .chm file. # normal table of contents (NO) in the .chm file.
BINARY_TOC = NO BINARY_TOC = NO
# The TOC_EXPAND flag can be set to YES to add extra items for group members # The TOC_EXPAND flag can be set to YES to add extra items for group members
# to the contents of the HTML help documentation and to the tree view. # to the contents of the HTML help documentation and to the tree view.
TOC_EXPAND = NO TOC_EXPAND = NO
# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and QHP_VIRTUAL_FOLDER # The DISABLE_INDEX tag can be used to turn on/off the condensed index at
# are set, an additional index file will be generated that can be used as input for # top of each HTML page. The value NO (the default) enables the index and
# Qt's qhelpgenerator to generate a Qt Compressed Help (.qch) of the generated
# HTML documentation.
GENERATE_QHP = NO
# If the QHG_LOCATION tag is specified, the QCH_FILE tag can
# be used to specify the file name of the resulting .qch file.
# The path specified is relative to the HTML output folder.
QCH_FILE =
# The QHP_NAMESPACE tag specifies the namespace to use when generating
# Qt Help Project output. For more information please see
# http://doc.trolltech.com/qthelpproject.html#namespace
QHP_NAMESPACE =
# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating
# Qt Help Project output. For more information please see
# http://doc.trolltech.com/qthelpproject.html#virtual-folders
QHP_VIRTUAL_FOLDER = doc
# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to add.
# For more information please see
# http://doc.trolltech.com/qthelpproject.html#custom-filters
QHP_CUST_FILTER_NAME =
# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the custom filter to add.For more information please see
# <a href="http://doc.trolltech.com/qthelpproject.html#custom-filters">Qt Help Project / Custom Filters</a>.
QHP_CUST_FILTER_ATTRS =
# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this project's
# filter section matches.
# <a href="http://doc.trolltech.com/qthelpproject.html#filter-attributes">Qt Help Project / Filter Attributes</a>.
QHP_SECT_FILTER_ATTRS =
# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can
# be used to specify the location of Qt's qhelpgenerator.
# If non-empty doxygen will try to run qhelpgenerator on the generated
# .qhp file.
QHG_LOCATION =
# The DISABLE_INDEX tag can be used to turn on/off the condensed index at
# top of each HTML page. The value NO (the default) enables the index and
# the value YES disables it. # the value YES disables it.
DISABLE_INDEX = NO DISABLE_INDEX = NO
# This tag can be used to set the number of enum values (range [1..20]) # This tag can be used to set the number of enum values (range [1..20])
# that doxygen will group on one line in the generated HTML documentation. # that doxygen will group on one line in the generated HTML documentation.
ENUM_VALUES_PER_LINE = 1 ENUM_VALUES_PER_LINE = 1
# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index # The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
# structure should be generated to display hierarchical information. # structure should be generated to display hierarchical information.
# If the tag value is set to FRAME, a side panel will be generated # If the tag value is set to FRAME, a side panel will be generated
# containing a tree-like index structure (just like the one that # containing a tree-like index structure (just like the one that
# is generated for HTML Help). For this to work a browser that supports # is generated for HTML Help). For this to work a browser that supports
# JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+, # JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+,
# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are # Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are
# probably better off using the HTML help feature. Other possible values # probably better off using the HTML help feature. Other possible values
# for this tag are: HIERARCHIES, which will generate the Groups, Directories, # for this tag are: HIERARCHIES, which will generate the Groups, Directories,
# and Class Hierarchy pages using a tree view instead of an ordered list; # and Class Hierarchy pages using a tree view instead of an ordered list;
# ALL, which combines the behavior of FRAME and HIERARCHIES; and NONE, which # ALL, which combines the behavior of FRAME and HIERARCHIES; and NONE, which
# disables this behavior completely. For backwards compatibility with previous # disables this behavior completely. For backwards compatibility with previous
# releases of Doxygen, the values YES and NO are equivalent to FRAME and NONE # releases of Doxygen, the values YES and NO are equivalent to FRAME and NONE
# respectively. # respectively.
GENERATE_TREEVIEW = NO GENERATE_TREEVIEW = NO
# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be # If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be
# used to set the initial width (in pixels) of the frame in which the tree # used to set the initial width (in pixels) of the frame in which the tree
# is shown. # is shown.
TREEVIEW_WIDTH = 250 TREEVIEW_WIDTH = 250
# Use this tag to change the font size of Latex formulas included # Use this tag to change the font size of Latex formulas included
# as images in the HTML documentation. The default is 10. Note that # as images in the HTML documentation. The default is 10. Note that
# when you change the font size after a successful doxygen run you need # when you change the font size after a successful doxygen run you need
# to manually remove any form_*.png images from the HTML output directory # to manually remove any form_*.png images from the HTML output directory
# to force them to be regenerated. # to force them to be regenerated.
FORMULA_FONTSIZE = 10 FORMULA_FONTSIZE = 10
#--------------------------------------------------------------------------- #---------------------------------------------------------------------------
# actor_system& system, const uration options related to the LaTeX output # Disable everything but HTML
#--------------------------------------------------------------------------- #---------------------------------------------------------------------------
# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will
# generate Latex output.
GENERATE_LATEX = NO GENERATE_LATEX = NO
# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put.
# If a relative path is entered the value of OUTPUT_DIRECTORY will be
# put in front of it. If left blank `latex' will be used as the default path.
LATEX_OUTPUT = latex
# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
# invoked. If left blank `latex' will be used as the default command name.
LATEX_CMD_NAME = latex
# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to
# generate index for LaTeX. If left blank `makeindex' will be used as the
# default command name.
MAKEINDEX_CMD_NAME = makeindex
# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact
# LaTeX documents. This may be useful for small projects and may help to
# save some trees in general.
COMPACT_LATEX = NO
# The PAPER_TYPE tag can be used to set the paper type that is used
# by the printer. Possible values are: a4, a4wide, letter, legal and
# executive. If left blank a4wide will be used.
PAPER_TYPE = a4wide
# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX
# packages that should be included in the LaTeX output.
EXTRA_PACKAGES =
# The LATEX_HEADER tag can be used to specify a personal LaTeX header for
# the generated latex document. The header should contain everything until
# the first chapter. If it is left blank doxygen will generate a
# standard header. Notice: only use this tag if you know what you are doing!
LATEX_HEADER =
# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated
# is prepared for conversion to pdf (using ps2pdf). The pdf file will
# contain links (just like the HTML output) instead of page references
# This makes the output suitable for online browsing using a pdf viewer.
PDF_HYPERLINKS = YES
# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of
# plain latex in the generated Makefile. Set this option to YES to get a
# higher quality PDF documentation.
USE_PDFLATEX = YES
# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode.
# command to the generated LaTeX files. This will instruct LaTeX to keep
# running if errors occur, instead of asking the user for help.
# This option is also used when generating formulas in HTML.
LATEX_BATCHMODE = NO
# If LATEX_HIDE_INDICES is set to YES then doxygen will not
# include the index chapters (such as File Index, Compound Index, etc.)
# in the output.
LATEX_HIDE_INDICES = NO
#---------------------------------------------------------------------------
# actor_system& system, const uration options related to the RTF output
#---------------------------------------------------------------------------
# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output
# The RTF output is optimized for Word 97 and may not look very pretty with
# other RTF readers or editors.
GENERATE_RTF = NO GENERATE_RTF = NO
# The RTF_OUTPUT tag is used to specify where the RTF docs will be put.
# If a relative path is entered the value of OUTPUT_DIRECTORY will be
# put in front of it. If left blank `rtf' will be used as the default path.
RTF_OUTPUT = rtf
# If the COMPACT_RTF tag is set to YES Doxygen generates more compact
# RTF documents. This may be useful for small projects and may help to
# save some trees in general.
COMPACT_RTF = NO
# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated
# will contain hyperlink fields. The RTF file will
# contain links (just like the HTML output) instead of page references.
# This makes the output suitable for online browsing using WORD or other
# programs which support those fields.
# Note: wordpad (write) and others do not support links.
RTF_HYPERLINKS = NO
# Load stylesheet definitions from file. Syntax is similar to doxygen's
# actor_system& system, const file, i.e. a series of assignments. You only have to provide
# replacements, missing definitions are set to their default value.
RTF_STYLESHEET_FILE =
# Set optional variables used in the generation of an rtf document.
# Syntax is similar to doxygen's actor_system& system, const file.
RTF_EXTENSIONS_FILE =
#---------------------------------------------------------------------------
# actor_system& system, const uration options related to the man page output
#---------------------------------------------------------------------------
# If the GENERATE_MAN tag is set to YES (the default) Doxygen will
# generate man pages
GENERATE_MAN = NO GENERATE_MAN = NO
# The MAN_OUTPUT tag is used to specify where the man pages will be put.
# If a relative path is entered the value of OUTPUT_DIRECTORY will be
# put in front of it. If left blank `man' will be used as the default path.
MAN_OUTPUT = man
# The MAN_EXTENSION tag determines the extension that is added to
# the generated man pages (default is the subroutine's section .3)
MAN_EXTENSION = .3
# If the MAN_LINKS tag is set to YES and Doxygen generates man output,
# then it will generate one additional man file for each entity
# documented in the real man page(s). These additional files
# only source the real man page, but without them the man command
# would be unable to find the correct page. The default is NO.
MAN_LINKS = NO
#---------------------------------------------------------------------------
# actor_system& system, const uration options related to the XML output
#---------------------------------------------------------------------------
# If the GENERATE_XML tag is set to YES Doxygen will
# generate an XML file that captures the structure of
# the code including all documentation.
GENERATE_XML = NO GENERATE_XML = NO
# The XML_OUTPUT tag is used to specify where the XML pages will be put.
# If a relative path is entered the value of OUTPUT_DIRECTORY will be
# put in front of it. If left blank `xml' will be used as the default path.
XML_OUTPUT = xml
# If the XML_PROGRAMLISTING tag is set to YES Doxygen will
# dump the program listings (including syntax highlighting
# and cross-referencing information) to the XML output. Note that
# enabling this will significantly increase the size of the XML output.
XML_PROGRAMLISTING = YES
#---------------------------------------------------------------------------
# actor_system& system, const uration options for the AutoGen Definitions output
#---------------------------------------------------------------------------
# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will
# generate an AutoGen Definitions (see autogen.sf.net) file
# that captures the structure of the code including all
# documentation. Note that this feature is still experimental
# and incomplete at the moment.
GENERATE_AUTOGEN_DEF = NO GENERATE_AUTOGEN_DEF = NO
#---------------------------------------------------------------------------
# actor_system& system, const uration options related to the Perl module output
#---------------------------------------------------------------------------
# If the GENERATE_PERLMOD tag is set to YES Doxygen will
# generate a Perl module file that captures the structure of
# the code including all documentation. Note that this
# feature is still experimental and incomplete at the
# moment.
GENERATE_PERLMOD = NO GENERATE_PERLMOD = NO
# If the PERLMOD_LATEX tag is set to YES Doxygen will generate GENERATE_DOCSET = NO
# the necessary Makefile rules, Perl scripts and LaTeX code to be able
# to generate PDF and DVI output from the Perl module output.
PERLMOD_LATEX = NO
# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be
# nicely formatted so it can be parsed by a human reader.
# This is useful
# if you want to understand what is going on.
# On the other hand, if this
# tag is set to NO the size of the Perl module output will be much smaller
# and Perl will parse it just the same.
PERLMOD_PRETTY = YES
# The names of the make variables in the generated doxyrules.make file
# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX.
# This is useful so different doxyrules.make files included by the same
# Makefile don't overwrite each other's variables.
PERLMOD_MAKEVAR_PREFIX = GENERATE_QHP = NO
#--------------------------------------------------------------------------- #---------------------------------------------------------------------------
# Configuration options related to the preprocessor # Configuration options related to the preprocessor
#--------------------------------------------------------------------------- #---------------------------------------------------------------------------
# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will # If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will
# evaluate all C-preprocessor directives found in the sources and include # evaluate all C-preprocessor directives found in the sources and include
# files. # files.
ENABLE_PREPROCESSING = YES ENABLE_PREPROCESSING = YES
# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro # If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro
# names in the source code. If set to NO (the default) only conditional # names in the source code. If set to NO (the default) only conditional
# compilation will be performed. Macro expansion can be done in a controlled # compilation will be performed. Macro expansion can be done in a controlled
# way by setting EXPAND_ONLY_PREDEF to YES. # way by setting EXPAND_ONLY_PREDEF to YES.
MACRO_EXPANSION = NO MACRO_EXPANSION = NO
# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES # If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES
# then the macro expansion is limited to the macros specified with the # then the macro expansion is limited to the macros specified with the
# PREDEFINED and EXPAND_AS_DEFINED tags. # PREDEFINED and EXPAND_AS_DEFINED tags.
EXPAND_ONLY_PREDEF = NO EXPAND_ONLY_PREDEF = NO
# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files # If the SEARCH_INCLUDES tag is set to YES (the default) the includes files
# in the INCLUDE_PATH (see below) will be search if a #include is found. # in the INCLUDE_PATH (see below) will be search if a #include is found.
SEARCH_INCLUDES = YES SEARCH_INCLUDES = YES
# The INCLUDE_PATH tag can be used to specify one or more directories that # The INCLUDE_PATH tag can be used to specify one or more directories that
# contain include files that are not input files but should be processed by # contain include files that are not input files but should be processed by
# the preprocessor. # the preprocessor.
INCLUDE_PATH = INCLUDE_PATH =
# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard # You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
# patterns (like *.h and *.hpp) to filter out the header-files in the # patterns (like *.h and *.hpp) to filter out the header-files in the
# directories. If left blank, the patterns specified with FILE_PATTERNS will # directories. If left blank, the patterns specified with FILE_PATTERNS will
# be used. # be used.
INCLUDE_FILE_PATTERNS = INCLUDE_FILE_PATTERNS =
# The PREDEFINED tag can be used to specify one or more macro names that # The PREDEFINED tag can be used to specify one or more macro names that
# are defined before the preprocessor is started (similar to the -D option of # are defined before the preprocessor is started (similar to the -D option of
# gcc). The argument of the tag is a list of macros of the form: name # gcc). The argument of the tag is a list of macros of the form: name
# or name=definition (no spaces). If the definition and the = are # or name=definition (no spaces). If the definition and the = are
# omitted =1 is assumed. To prevent a macro definition from being # omitted =1 is assumed. To prevent a macro definition from being
# undefined via #undef or recursively expanded use the := operator # undefined via #undef or recursively expanded use the := operator
# instead of the = operator. # instead of the = operator.
PREDEFINED = CAF_DOCUMENTATION PREDEFINED = CAF_DOCUMENTATION
# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then
# this tag can be used to specify a list of macro names that should be expanded. # this tag can be used to specify a list of macro names that should be expanded.
# The macro definition that is found in the sources will be used. # The macro definition that is found in the sources will be used.
# Use the PREDEFINED tag if you want to use a different macro definition. # Use the PREDEFINED tag if you want to use a different macro definition.
EXPAND_AS_DEFINED = EXPAND_AS_DEFINED =
# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then # If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then
# doxygen's preprocessor will remove all function-like macros that are alone # doxygen's preprocessor will remove all function-like macros that are alone
# on a line, have an all uppercase name, and do not end with a semicolon. Such # on a line, have an all uppercase name, and do not end with a semicolon. Such
# function macros are typically used for boiler-plate code, and will confuse # function macros are typically used for boiler-plate code, and will confuse
# the parser if not removed. # the parser if not removed.
SKIP_FUNCTION_MACROS = YES SKIP_FUNCTION_MACROS = YES
#--------------------------------------------------------------------------- #---------------------------------------------------------------------------
# Configuration::additions related to external references # Configuration::additions related to external references
#--------------------------------------------------------------------------- #---------------------------------------------------------------------------
# The TAGFILES option can be used to specify one or more tagfiles. # The TAGFILES option can be used to specify one or more tagfiles.
# Optionally an initial location of the external documentation # Optionally an initial location of the external documentation
# can be added for each tagfile. The format of a tag file without # can be added for each tagfile. The format of a tag file without
# this location is as follows: # this location is as follows:
# #
# TAGFILES = file1 file2 ... # TAGFILES = file1 file2 ...
# Adding location for the tag files is done as follows: # Adding location for the tag files is done as follows:
# #
# TAGFILES = file1=loc1 "file2 = loc2" ... # TAGFILES = file1=loc1 "file2 = loc2" ...
# where "loc1" and "loc2" can be relative or absolute paths or # where "loc1" and "loc2" can be relative or absolute paths or
# URLs. If a location is present for each tag, the installdox tool # URLs. If a location is present for each tag, the installdox tool
# does not have to be run to correct the links. # does not have to be run to correct the links.
# Note that each tag file must have a unique name # Note that each tag file must have a unique name
# (where the name does NOT include the path) # (where the name does NOT include the path)
# If a tag file is not located in the directory in which doxygen # If a tag file is not located in the directory in which doxygen
# is run, you must also specify the path to the tagfile here. # is run, you must also specify the path to the tagfile here.
TAGFILES = TAGFILES =
# When a file name is specified after GENERATE_TAGFILE, doxygen will create # When a file name is specified after GENERATE_TAGFILE, doxygen will create
# a tag file that is based on the input files it reads. # a tag file that is based on the input files it reads.
GENERATE_TAGFILE = GENERATE_TAGFILE =
# If the ALLEXTERNALS tag is set to YES all external classes will be listed # If the ALLEXTERNALS tag is set to YES all external classes will be listed
# in the class index. If set to NO only the inherited external classes # in the class index. If set to NO only the inherited external classes
# will be listed. # will be listed.
ALLEXTERNALS = NO ALLEXTERNALS = NO
# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed # If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed
# in the modules index. If set to NO, only the current project's groups will # in the modules index. If set to NO, only the current project's groups will
# be listed. # be listed.
EXTERNAL_GROUPS = YES EXTERNAL_GROUPS = YES
# The PERL_PATH should be the absolute path and name of the perl script # The PERL_PATH should be the absolute path and name of the perl script
# interpreter (i.e. the result of `which perl'). # interpreter (i.e. the result of `which perl').
PERL_PATH = /usr/bin/perl PERL_PATH = /usr/bin/perl
#--------------------------------------------------------------------------- #---------------------------------------------------------------------------
# Configuration options related to the dot tool # Configuration options related to the dot tool
#--------------------------------------------------------------------------- #---------------------------------------------------------------------------
# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will # If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will
# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base # generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base
# or super classes. Setting the tag to NO turns the diagrams off. Note that # or super classes. Setting the tag to NO turns the diagrams off. Note that
# this option is superseded by the HAVE_DOT option below. This is only a # this option is superseded by the HAVE_DOT option below. This is only a
# fallback. It is recommended to install and use dot, since it yields more # fallback. It is recommended to install and use dot, since it yields more
# powerful graphs. # powerful graphs.
CLASS_DIAGRAMS = YES CLASS_DIAGRAMS = YES
# You can define message sequence charts within doxygen comments using the \msc # You can define message sequence charts within doxygen comments using the \msc
# command. Doxygen will then run the mscgen tool (see # command. Doxygen will then run the mscgen tool (see
# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the # http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the
# documentation. The MSCGEN_PATH tag allows you to specify the directory where # documentation. The MSCGEN_PATH tag allows you to specify the directory where
# the mscgen tool resides. If left empty the tool is assumed to be found in the # the mscgen tool resides. If left empty the tool is assumed to be found in the
# default search path. # default search path.
MSCGEN_PATH = MSCGEN_PATH =
# If set to YES, the inheritance and collaboration graphs will hide # If set to YES, the inheritance and collaboration graphs will hide
# inheritance and usage relations if the target is undocumented # inheritance and usage relations if the target is undocumented
# or is not a class. # or is not a class.
HIDE_UNDOC_RELATIONS = YES HIDE_UNDOC_RELATIONS = YES
# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is # If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
# available from the path. This tool is part of Graphviz, a graph visualization # available from the path. This tool is part of Graphviz, a graph visualization
# toolkit from AT&T and Lucent Bell Labs. The other options in this section # toolkit from AT&T and Lucent Bell Labs. The other options in this section
# have no effect if this option is set to NO (the default) # have no effect if this option is set to NO (the default)
HAVE_DOT = NO HAVE_DOT = NO
# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs. # The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs.
# The default size is 10pt. # The default size is 10pt.
DOT_FONTSIZE = 10 DOT_FONTSIZE = 10
# By default doxygen will tell dot to use the output directory to look for the # By default doxygen will tell dot to use the output directory to look for the
# FreeSans.ttf font (which doxygen will put there itself). If you specify a # FreeSans.ttf font (which doxygen will put there itself). If you specify a
# different font using DOT_FONTNAME you can set the path where dot # different font using DOT_FONTNAME you can set the path where dot
# can find it using this tag. # can find it using this tag.
DOT_FONTPATH = DOT_FONTPATH =
# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen # If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen
# will generate a graph for each documented class showing the direct and # will generate a graph for each documented class showing the direct and
# indirect inheritance relations. Setting this tag to YES will force the # indirect inheritance relations. Setting this tag to YES will force the
# the CLASS_DIAGRAMS tag to NO. # the CLASS_DIAGRAMS tag to NO.
CLASS_GRAPH = YES CLASS_GRAPH = YES
# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen # If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen
# will generate a graph for each documented class showing the direct and # will generate a graph for each documented class showing the direct and
# indirect implementation dependencies (inheritance, containment, and # indirect implementation dependencies (inheritance, containment, and
# class references variables) of the class with other documented classes. # class references variables) of the class with other documented classes.
COLLABORATION_GRAPH = YES COLLABORATION_GRAPH = YES
# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen # If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen
# will generate a graph for groups, showing the direct groups dependencies # will generate a graph for groups, showing the direct groups dependencies
GROUP_GRAPHS = YES GROUP_GRAPHS = YES
# If the UML_LOOK tag is set to YES doxygen will generate inheritance and # If the UML_LOOK tag is set to YES doxygen will generate inheritance and
# collaboration diagrams in a style similar to the OMG's Unified Modeling # collaboration diagrams in a style similar to the OMG's Unified Modeling
# Language. # Language.
UML_LOOK = YES UML_LOOK = YES
# If set to YES, the inheritance and collaboration graphs will show the # If set to YES, the inheritance and collaboration graphs will show the
# relations between templates and their instances. # relations between templates and their instances.
TEMPLATE_RELATIONS = YES TEMPLATE_RELATIONS = YES
# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT # If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT
# tags are set to YES then doxygen will generate a graph for each documented # tags are set to YES then doxygen will generate a graph for each documented
# file showing the direct and indirect include dependencies of the file with # file showing the direct and indirect include dependencies of the file with
# other documented files. # other documented files.
INCLUDE_GRAPH = YES INCLUDE_GRAPH = YES
# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and # If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and
# HAVE_DOT tags are set to YES then doxygen will generate a graph for each # HAVE_DOT tags are set to YES then doxygen will generate a graph for each
# documented header file showing the documented files that directly or # documented header file showing the documented files that directly or
# indirectly include this file. # indirectly include this file.
INCLUDED_BY_GRAPH = YES INCLUDED_BY_GRAPH = YES
# If the CALL_GRAPH and HAVE_DOT options are set to YES then # If the CALL_GRAPH and HAVE_DOT options are set to YES then
# doxygen will generate a call dependency graph for every global function # doxygen will generate a call dependency graph for every global function
# or class method. Note that enabling this option will significantly increase # or class method. Note that enabling this option will significantly increase
# the time of a run. So in most cases it will be better to enable call graphs # the time of a run. So in most cases it will be better to enable call graphs
# for selected functions only using the \callgraph command. # for selected functions only using the \callgraph command.
CALL_GRAPH = NO CALL_GRAPH = NO
# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then # If the CALLER_GRAPH and HAVE_DOT tags are set to YES then
# doxygen will generate a caller dependency graph for every global function # doxygen will generate a caller dependency graph for every global function
# or class method. Note that enabling this option will significantly increase # or class method. Note that enabling this option will significantly increase
# the time of a run. So in most cases it will be better to enable caller # the time of a run. So in most cases it will be better to enable caller
# graphs for selected functions only using the \callergraph command. # graphs for selected functions only using the \callergraph command.
CALLER_GRAPH = NO CALLER_GRAPH = NO
# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen # If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen
# will graphical hierarchy of all classes instead of a textual one. # will graphical hierarchy of all classes instead of a textual one.
GRAPHICAL_HIERARCHY = YES GRAPHICAL_HIERARCHY = YES
# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES # If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES
# then doxygen will show the dependencies a directory has on other directories # then doxygen will show the dependencies a directory has on other directories
# in a graphical way. The dependency relations are determined by the #include # in a graphical way. The dependency relations are determined by the #include
# relations between the files in the directories. # relations between the files in the directories.
DIRECTORY_GRAPH = YES DIRECTORY_GRAPH = YES
# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images # The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
# generated by dot. Possible values are png, jpg, or gif # generated by dot. Possible values are png, jpg, or gif
# If left blank png will be used. # If left blank png will be used.
DOT_IMAGE_FORMAT = png DOT_IMAGE_FORMAT = png
# The tag DOT_PATH can be used to specify the path where the dot tool can be # The tag DOT_PATH can be used to specify the path where the dot tool can be
# found. If left blank, it is assumed the dot tool can be found in the path. # found. If left blank, it is assumed the dot tool can be found in the path.
DOT_PATH = DOT_PATH =
# The DOTFILE_DIRS tag can be used to specify one or more directories that # The DOTFILE_DIRS tag can be used to specify one or more directories that
# contain dot files that are included in the documentation (see the # contain dot files that are included in the documentation (see the
# \dotfile command). # \dotfile command).
DOTFILE_DIRS = DOTFILE_DIRS =
# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of # The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of
# nodes that will be shown in the graph. If the number of nodes in a graph # nodes that will be shown in the graph. If the number of nodes in a graph
# becomes larger than this value, doxygen will truncate the graph, which is # becomes larger than this value, doxygen will truncate the graph, which is
# visualized by representing a node as a red box. Note that doxygen if the # visualized by representing a node as a red box. Note that doxygen if the
# number of direct children of the root node in a graph is already larger than # number of direct children of the root node in a graph is already larger than
# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note # DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note
# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. # that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
DOT_GRAPH_MAX_NODES = 50 DOT_GRAPH_MAX_NODES = 50
# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the # The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the
# graphs generated by dot. A depth value of 3 means that only nodes reachable # graphs generated by dot. A depth value of 3 means that only nodes reachable
# from the root by following a path via at most 3 edges will be shown. Nodes # from the root by following a path via at most 3 edges will be shown. Nodes
# that lay further from the root node will be omitted. Note that setting this # that lay further from the root node will be omitted. Note that setting this
# option to 1 or 2 may greatly reduce the computation time needed for large # option to 1 or 2 may greatly reduce the computation time needed for large
# code bases. Also note that the size of a graph can be further restricted by # code bases. Also note that the size of a graph can be further restricted by
# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. # DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
MAX_DOT_GRAPH_DEPTH = 0 MAX_DOT_GRAPH_DEPTH = 0
# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent # Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
# background. This is disabled by default, because dot on Windows does not # background. This is disabled by default, because dot on Windows does not
# seem to support this out of the box. Warning: Depending on the platform used, # seem to support this out of the box. Warning: Depending on the platform used,
# enabling this option may lead to badly anti-aliased labels on the edges of # enabling this option may lead to badly anti-aliased labels on the edges of
# a graph (i.e. they become hard to read). # a graph (i.e. they become hard to read).
DOT_TRANSPARENT = NO DOT_TRANSPARENT = NO
# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output # Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output
# files in one run (i.e. multiple -o and -T options on the command line). This # files in one run (i.e. multiple -o and -T options on the command line). This
# makes dot run faster, but since only newer versions of dot (>1.8.10) # makes dot run faster, but since only newer versions of dot (>1.8.10)
# support this, this feature is disabled by default. # support this, this feature is disabled by default.
DOT_MULTI_TARGETS = NO DOT_MULTI_TARGETS = NO
# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will # If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will
# generate a legend page explaining the meaning of the various boxes and # generate a legend page explaining the meaning of the various boxes and
# arrows in the dot generated graphs. # arrows in the dot generated graphs.
GENERATE_LEGEND = YES GENERATE_LEGEND = YES
# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will # If the DOT_CLEANUP tag is set to YES (the default) Doxygen will
# remove the intermediate dot files that are used to generate # remove the intermediate dot files that are used to generate
# the various graphs. # the various graphs.
DOT_CLEANUP = YES DOT_CLEANUP = YES
...@@ -1466,7 +1195,7 @@ DOT_CLEANUP = YES ...@@ -1466,7 +1195,7 @@ DOT_CLEANUP = YES
# Options related to the search engine # Options related to the search engine
#--------------------------------------------------------------------------- #---------------------------------------------------------------------------
# The SEARCHENGINE tag specifies whether or not a search engine should be # The SEARCHENGINE tag specifies whether or not a search engine should be
# used. If set to NO the values of all tags below this one will be ignored. # used. If set to NO the values of all tags below this one will be ignored.
SEARCHENGINE = YES SEARCHENGINE = YES
# File: UseLATEX.cmake
# CMAKE commands to actually use the LaTeX compiler
# Version: 2.4.8
# Author: Kenneth Moreland <kmorel@sandia.gov>
#
# Copyright 2004, 2015 Sandia Corporation.
# Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive
# license for use of this work by or on behalf of the U.S. Government.
#
# This software is released under the BSD 3-Clause License.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
# 1. Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# 3. Neither the name of the copyright holder nor the names of its
# contributors may be used to endorse or promote products derived from this
# software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
# IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
#
# The following function is defined:
#
# add_latex_document(<tex_file>
# [BIBFILES <bib_files>]
# [INPUTS <input_tex_files>]
# [IMAGE_DIRS] <image_directories>
# [IMAGES] <image_files>
# [CONFIGURE] <tex_files>
# [DEPENDS] <tex_files>
# [MULTIBIB_NEWCITES] <suffix_list>
# [USE_BIBLATEX]
# [USE_INDEX]
# [INDEX_NAMES <index_names>]
# [USE_GLOSSARY] [USE_NOMENCL]
# [FORCE_PDF] [FORCE_DVI] [FORCE_HTML]
# [TARGET_NAME] <name>
# [EXCLUDE_FROM_ALL]
# [EXCLUDE_FROM_DEFAULTS])
# Adds targets that compile <tex_file>. The latex output is placed
# in LATEX_OUTPUT_PATH or CMAKE_CURRENT_BINARY_DIR if the former is
# not set. The latex program is picky about where files are located,
# so all input files are copied from the source directory to the
# output directory. This includes the target tex file, any tex file
# listed with the INPUTS option, the bibliography files listed with
# the BIBFILES option, and any .cls, .bst, .clo, .sty, .ist, and .fd
# files found in the current source directory. Images found in the
# IMAGE_DIRS directories or listed by IMAGES are also copied to the
# output directory and converted to an appropriate format if necessary.
# Any tex files also listed with the CONFIGURE option are also processed
# with the CMake CONFIGURE_FILE command (with the @ONLY flag). Any file
# listed in CONFIGURE but not the target tex file or listed with INPUTS
# has no effect. DEPENDS can be used to specify generated files that are
# needed to compile the latex target.
#
# The following targets are made. The name prefix is based off of the
# base name of the tex file unless TARGET_NAME is specified. If
# TARGET_NAME is specified, then that name is used for the targets.
#
# name_dvi: Makes <name>.dvi
# name_pdf: Makes <name>.pdf using pdflatex.
# name_safepdf: Makes <name>.pdf using ps2pdf. If using the
# default program arguments, this will ensure all fonts
# are embedded and no lossy compression has been
# performed on images.
# name_ps: Makes <name>.ps
# name_html: Makes <name>.html
# name_auxclean: Deletes <name>.aux and other auxiliary files.
# This is sometimes necessary if a LaTeX error occurs
# and writes a bad aux file. Unlike the regular clean
# target, it does not delete other input files, such as
# converted images, to save time on the rebuild.
#
# Unless the EXCLUDE_FROM_ALL option is given, one of these targets
# is added to the ALL target and built by default. Which target is
# determined by the LATEX_DEFAULT_BUILD CMake variable. See the
# documentation of that variable for more details.
#
# Unless the EXCLUDE_FROM_DEFAULTS option is given, all these targets
# are added as dependencies to targets named dvi, pdf, safepdf, ps,
# html, and auxclean, respectively.
#
# USE_BIBLATEX enables the use of biblatex/biber as an alternative to
# bibtex. Bibtex remains the default if USE_BIBLATEX is not
# specified.
#
# If the argument USE_INDEX is given, then commands to build an index
# are made. If the argument INDEX_NAMES is given, an index file is
# generated for each name in this list. See the LaTeX package multind
# for more information about how to generate multiple indices.
#
# If the argument USE_GLOSSARY is given, then commands to
# build a glossary are made. If the argument MULTIBIB_NEWCITES is
# given, then additional bibtex calls are added to the build to
# support the extra auxiliary files created with the \newcite command
# in the multibib package.
#
# History:
#
# 2.4.8 Fix synctex issue with absolute paths not being converted.
#
# 2.4.7 Fix some issues with spaces in the path of the working directory where
# LaTeX is executed.
#
# 2.4.6 Fix parse issue with older versions of CMake.
#
# 2.4.5 Fix issues with files and paths containing spaces.
#
# 2.4.4 Improve error reporting message when LaTeX fails.
#
# When LaTeX fails, delete the output file, which is invalid.
#
# Add warnings for "missing characters." These usually mean that a
# non-ASCII character is in the document and will not be printed
# correctly.
#
# 2.4.3 Check for warnings from the natbib package. When using natbib,
# warnings for missing bibliography references look different. So
# far, natbib seems to be quiet unless something is important, so
# look for all natbib warnings. (We can change this later if
# necessary.)
#
# 2.4.2 Fix an issue where new versions of ImageMagick expect the order of
# options in command line execution of magick/convert. (See, for
# example, http://www.imagemagick.org/Usage/basics/#why.)
#
# 2.4.1 Add ability to dump LaTeX log file when using batch mode. Batch
# mode suppresses most output, often including error messages. To
# make sure critical error messages get displayed, show the full log
# on failures.
#
# 2.4.0 Remove "-r 600" from the default PDFTOPS_CONVERTER_FLAGS. The -r flag
# is available from the Poppler version of pdftops, but not the Xpdf
# version.
#
# Fix an issue with the flags for the different programs not being
# properly separated.
#
# Fix an issue on windows where the = character is not allowed for
# ps2pdf arguments.
#
# Change default arguments for latex and pdflatex commands. Makes the
# output more quiet and prints out the file/line where errors occur.
# (Thanks to Nikos Koukis.)
#
# After a LaTeX build, check the log file for warnings that are
# indicative of problems with the build.
#
# Remove support for latex2html. Instead, use the htlatex program.
# This is now part of TeX Live and most other distributions. It also
# behaves much more like the other LaTeX programs. Also fixed some
# nasty issues with the htlatex arguments.
#
# 2.3.2 Declare LaTeX input files as sources for targets so that they show
# up in IDEs like QtCreator.
#
# Fix issue where main tex files in subdirectories were creating
# invalid targets for building HTML. Just disable the HTML targets in
# this case.
#
# 2.3.1 Support use of magick command instead of convert command for
# ImageMagick 7.
#
# 2.3.0 Add USE_BIBLATEX option to support the biblatex package, which
# requires using the program biber as a replacement for bibtex
# (thanks to David Tracey).
#
# 2.2.1 Add STRINGS property to LATEX_DEFAULT_BUILD to make it easier to
# select the default build in the CMake GUI.
#
# 2.2.0 Add TARGET_NAME option.
#
# 2.1.1 Support for finding bmp, ppm, and other image files.
#
# 2.1.0 Fix an error where the pdf target and others were defined multiple
# times if UseLATEX.cmake was included multiple times.
#
# Added INDEX_NAMES option to support multiple indexes in a single
# document from the multind package (thanks to Dan Lipsa).
#
# 2.0.0 First major revision of UseLATEX.cmake updates to more recent features
# of CMake and some non-backward compatible changes.
#
# Changed all function and macro names to lower case. CMake's identifiers
# are case insensitive, but the convention moved from all upper case to
# all lower case somewhere around the release of CMake 2. (The original
# version of UseLATEX.cmake predates that.)
#
# Remove condition matching in if statements. They are no longer necessary
# and are even discouraged (because else clauses get confusing).
#
# Use "new" features available in CMake such as list and argument parsing.
#
# Remove some code that has been deprecated for a while.
#
# Mark variables for compiler and converter executables as advanced to
# match the more conventional CMake behavior.
#
# Changed how default builds are specified and add the ability to force
# a particular build.
#
# Made the base targets (pdf, dvi, etc.) global. add_latex_document
# always mangles its target names and these base targets depend on
# the targets with mangled names.
#
# 1.10.5 Fix for Window's convert check (thanks to Martin Baute).
#
# 1.10.4 Copy font files to binary directory for packages that come with
# their own fonts.
#
# 1.10.3 Check for Windows version of convert being used instead of
# ImageMagick's version (thanks to Martin Baute).
#
# 1.10.2 Use htlatex as a fallback when latex2html is not available (thanks
# to Tomasz Grzegurzko).
#
# 1.10.1 Make convert program mandatory only if actually used (thanks to
# Julien Schueller).
#
# 1.10.0 Added NO_DEFAULT and DEFAULT_PS options.
# Fixed issue with cleaning files for LaTeX documents originating in
# a subdirectory.
#
# 1.9.6 Fixed problem with LATEX_SMALL_IMAGES.
# Strengthened check to make sure the output directory does not contain
# the source files.
#
# 1.9.5 Add support for image types not directly supported by either latex
# or pdflatex. (Thanks to Jorge Gerardo Pena Pastor for SVG support.)
#
# 1.9.4 Fix issues with filenames containing multiple periods.
#
# 1.9.3 Hide some variables that are now cached but should not show up in
# the ccmake list of variables.
#
# 1.9.2 Changed MACRO declarations to FUNCTION declarations. The better
# FUNCTION scoping will hopefully avoid some common but subtle bugs.
# This implicitly increases the minimum CMake version to 4.6 (although
# I honestly only test it with the latest 4.8 version).
#
# Since we are updating the minimum CMake version, I'm going to start
# using the builtin LIST commands that are now available.
#
# Favor using pdftops from the Poppler package to convert from pdf to
# eps. It does a much better job than ImageMagick or ghostscript.
#
# 1.9.1 Fixed typo that caused the LATEX_SMALL_IMAGES option to fail to
# activate.
#
# 1.9.0 Add support for the multibib package (thanks to Antonio LaTorre).
#
# 1.8.2 Fix corner case when an argument name was also a variable containing
# the text of an argument. In this case, the CMake IF was matching
# the argument text with the contents of the variable with the same
# argument name.
#
# 1.8.1 Fix problem where ps2pdf was not getting the appropriate arguments.
#
# 1.8.0 Add support for synctex.
#
# 1.7.7 Support calling xindy when making glossaries.
#
# Improved make clean support.
#
# 1.7.6 Add support for the nomencl package (thanks to Myles English).
#
# 1.7.5 Fix issue with bibfiles being copied two different ways, which causes
# Problems with dependencies (thanks to Edwin van Leeuwen).
#
# 1.7.4 Added the DEFAULT_SAFEPDF option (thanks to Raymond Wan).
#
# Added warnings when image directories are not found (and were
# probably not given relative to the source directory).
#
# 1.7.3 Fix some issues with interactions between makeglossaries and bibtex
# (thanks to Mark de Wever).
#
# 1.7.2 Use ps2pdf to convert eps to pdf to get around the problem with
# ImageMagick dropping the bounding box (thanks to Lukasz Lis).
#
# 1.7.1 Fixed some dependency issues.
#
# 1.7.0 Added DEPENDS options (thanks to Theodore Papadopoulo).
#
# 1.6.1 Ported the makeglossaries command to CMake and embedded the port
# into UseLATEX.cmake.
#
# 1.6.0 Allow the use of the makeglossaries command. Thanks to Oystein
# S. Haaland for the patch.
#
# 1.5.0 Allow any type of file in the INPUTS lists, not just tex file
# (suggested by Eric Noulard). As a consequence, the ability to
# specify tex files without the .tex extension is removed. The removed
# function is of dubious value anyway.
#
# When copying input files, skip over any file that exists in the
# binary directory but does not exist in the source directory with the
# assumption that these files were added by some other mechanism. I
# find this useful when creating large documents with multiple
# chapters that I want to build separately (for speed) as I work on
# them. I use the same boilerplate as the starting point for all
# and just copy it with different configurations. This was what the
# separate ADD_LATEX_DOCUMENT method was supposed to originally be for.
# Since its external use is pretty much deprecated, I removed that
# documentation.
#
# 1.4.1 Copy .sty files along with the other class and package files.
#
# 1.4.0 Added a MANGLE_TARGET_NAMES option that will mangle the target names.
#
# Fixed problem with copying bib files that became apparent with
# CMake 2.4.
#
# 1.3.0 Added a LATEX_OUTPUT_PATH variable that allows you or the user to
# specify where the built latex documents to go. This is especially
# handy if you want to do in-source builds.
#
# Removed the ADD_LATEX_IMAGES macro and absorbed the functionality
# into ADD_LATEX_DOCUMENT. The old interface was always kind of
# clunky anyway since you had to specify the image directory in both
# places. It also made supporting LATEX_OUTPUT_PATH problematic.
#
# Added support for jpeg files.
#
# 1.2.0 Changed the configuration options yet again. Removed the NO_CONFIGURE
# Replaced it with a CONFIGURE option that lists input files for which
# configure should be run.
#
# The pdf target no longer depends on the dvi target. This allows you
# to build latex documents that require pdflatex. Also added an option
# to make the pdf target the default one.
#
# 1.1.1 Added the NO_CONFIGURE option. The @ character can be used when
# specifying table column separators. If two or more are used, then
# will incorrectly substitute them.
#
# 1.1.0 Added ability include multiple bib files. Added ability to do copy
# sub-tex files for multipart tex files.
#
# 1.0.0 If both ps and pdf type images exist, just copy the one that
# matches the current render mode. Replaced a bunch of STRING
# commands with GET_FILENAME_COMPONENT commands that were made to do
# the desired function.
#
# 0.4.0 First version posted to CMake Wiki.
#
if(__USE_LATEX_INCLUDED)
return()
endif()
set(__USE_LATEX_INCLUDED TRUE)
#############################################################################
# Find the location of myself while originally executing. If you do this
# inside of a macro, it will recode where the macro was invoked.
#############################################################################
set(LATEX_USE_LATEX_LOCATION ${CMAKE_CURRENT_LIST_FILE}
CACHE INTERNAL "Location of UseLATEX.cmake file." FORCE
)
#############################################################################
# Generic helper functions
#############################################################################
include(CMakeParseArguments)
function(latex_list_contains var value)
set(input_list ${ARGN})
list(FIND input_list "${value}" index)
if(index GREATER -1)
set(${var} TRUE PARENT_SCOPE)
else()
set(${var} PARENT_SCOPE)
endif()
endfunction(latex_list_contains)
# Match the contents of a file to a regular expression.
function(latex_file_match variable filename regexp default)
# The FILE STRINGS command would be a bit better, but I'm not totally sure
# the match will always be to a whole line, and I don't want to break things.
file(READ ${filename} file_contents)
string(REGEX MATCHALL "${regexp}"
match_result ${file_contents}
)
if(match_result)
set(${variable} "${match_result}" PARENT_SCOPE)
else()
set(${variable} "${default}" PARENT_SCOPE)
endif()
endfunction(latex_file_match)
# A version of GET_FILENAME_COMPONENT that treats extensions after the last
# period rather than the first. To the best of my knowledge, all filenames
# typically used by LaTeX, including image files, have small extensions
# after the last dot.
function(latex_get_filename_component varname filename type)
set(result)
if("${type}" STREQUAL "NAME_WE")
get_filename_component(name ${filename} NAME)
string(REGEX REPLACE "\\.[^.]*\$" "" result "${name}")
elseif("${type}" STREQUAL "EXT")
get_filename_component(name ${filename} NAME)
string(REGEX MATCH "\\.[^.]*\$" result "${name}")
else()
get_filename_component(result ${filename} ${type})
endif()
set(${varname} "${result}" PARENT_SCOPE)
endfunction(latex_get_filename_component)
#############################################################################
# Functions that perform processing during a LaTeX build.
#############################################################################
function(latex_execute_latex)
if(NOT LATEX_TARGET)
message(SEND_ERROR "Need to define LATEX_TARGET")
endif()
if(NOT LATEX_WORKING_DIRECTORY)
message(SEND_ERROR "Need to define LATEX_WORKING_DIRECTORY")
endif()
if(NOT LATEX_FULL_COMMAND)
message(SEND_ERROR "Need to define LATEX_FULL_COMMAND")
endif()
if(NOT LATEX_OUTPUT_FILE)
message(SEND_ERROR "Need to define LATEX_OUTPUT_FILE")
endif()
set(full_command_original "${LATEX_FULL_COMMAND}")
# Chose the native method for parsing command arguments. Newer versions of
# CMake allow you to just use NATIVE_COMMAND.
if (CMAKE_VERSION VERSION_GREATER 3.8)
set(separate_arguments_mode NATIVE_COMMAND)
else()
if (WIN32)
set(separate_arguments_mode WINDOWS_COMMAND)
else()
set(separate_arguments_mode UNIX_COMMAND)
endif()
endif()
# Preps variables for use in execute_process.
# Even though we expect LATEX_WORKING_DIRECTORY to have a single "argument,"
# we also want to make sure that we strip out any escape characters that can
# foul up the WORKING_DIRECTORY argument.
separate_arguments(LATEX_FULL_COMMAND UNIX_COMMAND "${LATEX_FULL_COMMAND}")
separate_arguments(LATEX_WORKING_DIRECTORY_SEP UNIX_COMMAND "${LATEX_WORKING_DIRECTORY}")
execute_process(
COMMAND ${LATEX_FULL_COMMAND}
WORKING_DIRECTORY "${LATEX_WORKING_DIRECTORY_SEP}"
RESULT_VARIABLE execute_result
)
if(NOT ${execute_result} EQUAL 0)
# LaTeX tends to write a file when a failure happens. Delete that file so
# that LaTeX will run again.
file(REMOVE "${LATEX_WORKING_DIRECTORY}/${LATEX_OUTPUT_FILE}")
message("\n\nLaTeX command failed")
message("${full_command_original}")
message("Log output:")
file(READ "${LATEX_WORKING_DIRECTORY}/${LATEX_TARGET}.log" log_output)
message("${log_output}")
message(FATAL_ERROR
"Successfully executed LaTeX, but LaTeX returned an error.")
endif()
endfunction(latex_execute_latex)
function(latex_makeglossaries)
# This is really a bare bones port of the makeglossaries perl script into
# CMake scripting.
message("**************************** In makeglossaries")
if(NOT LATEX_TARGET)
message(SEND_ERROR "Need to define LATEX_TARGET")
endif()
set(aux_file ${LATEX_TARGET}.aux)
if(NOT EXISTS ${aux_file})
message(SEND_ERROR "${aux_file} does not exist. Run latex on your target file.")
endif()
latex_file_match(newglossary_lines ${aux_file}
"@newglossary[ \t]*{([^}]*)}{([^}]*)}{([^}]*)}{([^}]*)}"
"@newglossary{main}{glg}{gls}{glo}"
)
latex_file_match(istfile_line ${aux_file}
"@istfilename[ \t]*{([^}]*)}"
"@istfilename{${LATEX_TARGET}.ist}"
)
string(REGEX REPLACE "@istfilename[ \t]*{([^}]*)}" "\\1"
istfile ${istfile_line}
)
string(REGEX MATCH ".*\\.xdy" use_xindy "${istfile}")
if(use_xindy)
message("*************** Using xindy")
if(NOT XINDY_COMPILER)
message(SEND_ERROR "Need to define XINDY_COMPILER")
endif()
else()
message("*************** Using makeindex")
if(NOT MAKEINDEX_COMPILER)
message(SEND_ERROR "Need to define MAKEINDEX_COMPILER")
endif()
endif()
foreach(newglossary ${newglossary_lines})
string(REGEX REPLACE
"@newglossary[ \t]*{([^}]*)}{([^}]*)}{([^}]*)}{([^}]*)}"
"\\1" glossary_name ${newglossary}
)
string(REGEX REPLACE
"@newglossary[ \t]*{([^}]*)}{([^}]*)}{([^}]*)}{([^}]*)}"
"${LATEX_TARGET}.\\2" glossary_log ${newglossary}
)
string(REGEX REPLACE
"@newglossary[ \t]*{([^}]*)}{([^}]*)}{([^}]*)}{([^}]*)}"
"${LATEX_TARGET}.\\3" glossary_out ${newglossary}
)
string(REGEX REPLACE
"@newglossary[ \t]*{([^}]*)}{([^}]*)}{([^}]*)}{([^}]*)}"
"${LATEX_TARGET}.\\4" glossary_in ${newglossary}
)
if(use_xindy)
latex_file_match(xdylanguage_line ${aux_file}
"@xdylanguage[ \t]*{${glossary_name}}{([^}]*)}"
"@xdylanguage{${glossary_name}}{english}"
)
string(REGEX REPLACE
"@xdylanguage[ \t]*{${glossary_name}}{([^}]*)}"
"\\1"
language
${xdylanguage_line}
)
# What crazy person makes a LaTeX index generator that uses different
# identifiers for language than babel (or at least does not support
# the old ones)?
if(${language} STREQUAL "frenchb")
set(language "french")
elseif(${language} MATCHES "^n?germanb?$")
set(language "german")
elseif(${language} STREQUAL "magyar")
set(language "hungarian")
elseif(${language} STREQUAL "lsorbian")
set(language "lower-sorbian")
elseif(${language} STREQUAL "norsk")
set(language "norwegian")
elseif(${language} STREQUAL "portuges")
set(language "portuguese")
elseif(${language} STREQUAL "russianb")
set(language "russian")
elseif(${language} STREQUAL "slovene")
set(language "slovenian")
elseif(${language} STREQUAL "ukraineb")
set(language "ukrainian")
elseif(${language} STREQUAL "usorbian")
set(language "upper-sorbian")
endif()
if(language)
set(language_flags "-L ${language}")
else()
set(language_flags "")
endif()
latex_file_match(codepage_line ${aux_file}
"@gls@codepage[ \t]*{${glossary_name}}{([^}]*)}"
"@gls@codepage{${glossary_name}}{utf}"
)
string(REGEX REPLACE
"@gls@codepage[ \t]*{${glossary_name}}{([^}]*)}"
"\\1"
codepage
${codepage_line}
)
if(codepage)
set(codepage_flags "-C ${codepage}")
else()
# Ideally, we would check that the language is compatible with the
# default codepage, but I'm hoping that distributions will be smart
# enough to specify their own codepage. I know, it's asking a lot.
set(codepage_flags "")
endif()
message("${XINDY_COMPILER} ${MAKEGLOSSARIES_COMPILER_ARGS} ${language_flags} ${codepage_flags} -I xindy -M ${glossary_name} -t ${glossary_log} -o ${glossary_out} ${glossary_in}"
)
exec_program(${XINDY_COMPILER}
ARGS ${MAKEGLOSSARIES_COMPILER_ARGS}
${language_flags}
${codepage_flags}
-I xindy
-M ${glossary_name}
-t ${glossary_log}
-o ${glossary_out}
${glossary_in}
OUTPUT_VARIABLE xindy_output
)
message("${xindy_output}")
# So, it is possible (perhaps common?) for aux files to specify a
# language and codepage that are incompatible with each other. Check
# for that condition, and if it happens run again with the default
# codepage.
if("${xindy_output}" MATCHES "^Cannot locate xindy module for language (.+) in codepage (.+)\\.$")
message("*************** Retrying xindy with default codepage.")
exec_program(${XINDY_COMPILER}
ARGS ${MAKEGLOSSARIES_COMPILER_ARGS}
${language_flags}
-I xindy
-M ${glossary_name}
-t ${glossary_log}
-o ${glossary_out}
${glossary_in}
)
endif()
else()
message("${MAKEINDEX_COMPILER} ${MAKEGLOSSARIES_COMPILER_ARGS} -s ${istfile} -t ${glossary_log} -o ${glossary_out} ${glossary_in}")
exec_program(${MAKEINDEX_COMPILER} ARGS ${MAKEGLOSSARIES_COMPILER_ARGS}
-s ${istfile} -t ${glossary_log} -o ${glossary_out} ${glossary_in}
)
endif()
endforeach(newglossary)
endfunction(latex_makeglossaries)
function(latex_makenomenclature)
message("**************************** In makenomenclature")
if(NOT LATEX_TARGET)
message(SEND_ERROR "Need to define LATEX_TARGET")
endif()
if(NOT MAKEINDEX_COMPILER)
message(SEND_ERROR "Need to define MAKEINDEX_COMPILER")
endif()
set(nomencl_out ${LATEX_TARGET}.nls)
set(nomencl_in ${LATEX_TARGET}.nlo)
exec_program(${MAKEINDEX_COMPILER} ARGS ${MAKENOMENCLATURE_COMPILER_ARGS}
${nomencl_in} -s "nomencl.ist" -o ${nomencl_out}
)
endfunction(latex_makenomenclature)
function(latex_correct_synctex)
message("**************************** In correct SyncTeX")
if(NOT LATEX_TARGET)
message(SEND_ERROR "Need to define LATEX_TARGET")
endif()
if(NOT GZIP)
message(SEND_ERROR "Need to define GZIP")
endif()
if(NOT LATEX_SOURCE_DIRECTORY)
message(SEND_ERROR "Need to define LATEX_SOURCE_DIRECTORY")
endif()
if(NOT LATEX_BINARY_DIRECTORY)
message(SEND_ERROR "Need to define LATEX_BINARY_DIRECTORY")
endif()
message("${LATEX_BINARY_DIRECTORY}")
message("${LATEX_SOURCE_DIRECTORY}")
set(synctex_file ${LATEX_BINARY_DIRECTORY}/${LATEX_TARGET}.synctex)
set(synctex_file_gz ${synctex_file}.gz)
if(EXISTS ${synctex_file_gz})
message("Making backup of synctex file.")
configure_file(${synctex_file_gz} ${synctex_file}.bak.gz COPYONLY)
message("Uncompressing synctex file.")
exec_program(${GZIP}
ARGS --decompress ${synctex_file_gz}
)
message("Reading synctex file.")
file(READ ${synctex_file} synctex_data)
message("Replacing output paths with input paths.")
foreach(extension tex cls bst clo sty ist fd)
# Relative paths
string(REGEX REPLACE
"(Input:[0-9]+:)([^/\n][^\n]\\.${extension}*)"
"\\1${LATEX_SOURCE_DIRECTORY}/\\2"
synctex_data
"${synctex_data}"
)
# Absolute paths
string(REGEX REPLACE
"(Input:[0-9]+:)${LATEX_BINARY_DIRECTORY}([^\n]*\\.${extension})"
"\\1${LATEX_SOURCE_DIRECTORY}\\2"
synctex_data
"${synctex_data}"
)
endforeach(extension)
message("Writing synctex file.")
file(WRITE ${synctex_file} "${synctex_data}")
message("Compressing synctex file.")
exec_program(${GZIP}
ARGS ${synctex_file}
)
else()
message(SEND_ERROR "File ${synctex_file_gz} not found. Perhaps synctex is not supported by your LaTeX compiler.")
endif()
endfunction(latex_correct_synctex)
function(latex_check_important_warnings)
set(log_file ${LATEX_TARGET}.log)
message("\nChecking ${log_file} for important warnings.")
if(NOT LATEX_TARGET)
message(SEND_ERROR "Need to define LATEX_TARGET")
endif()
if(NOT EXISTS ${log_file})
message("Could not find log file: ${log_file}")
return()
endif()
set(found_error)
file(READ ${log_file} log)
# Check for undefined references
string(REGEX MATCHALL
"\n[^\n]*Reference[^\n]*undefined[^\n]*"
reference_warnings
"${log}")
if(reference_warnings)
set(found_error TRUE)
message("\nFound missing reference warnings.")
foreach(warning ${reference_warnings})
string(STRIP "${warning}" warning_no_newline)
message("${warning_no_newline}")
endforeach(warning)
endif()
# Check for natbib warnings
string(REGEX MATCHALL
"\nPackage natbib Warning:[^\n]*"
natbib_warnings
"${log}")
if(natbib_warnings)
set(found_error TRUE)
message("\nFound natbib package warnings.")
foreach(warning ${natbib_warnings})
string(STRIP "${warning}" warning_no_newline)
message("${warning_no_newline}")
endforeach(warning)
endif()
# Check for overfull
string(REGEX MATCHALL
"\nOverfull[^\n]*"
overfull_warnings
"${log}")
if(overfull_warnings)
set(found_error TRUE)
message("\nFound overfull warnings. These are indicative of layout errors.")
foreach(warning ${overfull_warnings})
string(STRIP "${warning}" warning_no_newline)
message("${warning_no_newline}")
endforeach(warning)
endif()
# Check for invalid characters
string(REGEX MATCHALL
"\nMissing character:[^\n]*"
invalid_character_warnings
"${log}")
if(invalid_character_warnings)
set(found_error TRUE)
message("\nFound invalid character warnings. These characters are likely not printed correctly.")
foreach(warning ${invalid_character_warnings})
string(STRIP "${warning}" warning_no_newline)
message("${warning_no_newline}")
endforeach(warning)
endif()
if(found_error)
latex_get_filename_component(log_file_path ${log_file} ABSOLUTE)
message("\nConsult ${log_file_path} for more information on LaTeX build.")
else()
message("No known important warnings found.")
endif(found_error)
endfunction(latex_check_important_warnings)
#############################################################################
# Helper functions for establishing LaTeX build.
#############################################################################
function(latex_needit VAR NAME)
if(NOT ${VAR})
message(SEND_ERROR "I need the ${NAME} command.")
endif()
endfunction(latex_needit)
function(latex_wantit VAR NAME)
if(NOT ${VAR})
message(STATUS "I could not find the ${NAME} command.")
endif()
endfunction(latex_wantit)
function(latex_setup_variables)
set(LATEX_OUTPUT_PATH "${LATEX_OUTPUT_PATH}"
CACHE PATH "If non empty, specifies the location to place LaTeX output."
)
find_package(LATEX)
find_program(XINDY_COMPILER
NAME xindy
PATHS ${MIKTEX_BINARY_PATH} /usr/bin
)
find_package(UnixCommands)
find_program(PDFTOPS_CONVERTER
NAMES pdftops
DOC "The pdf to ps converter program from the Poppler package."
)
find_program(HTLATEX_COMPILER
NAMES htlatex
PATHS ${MIKTEX_BINARY_PATH}
/usr/bin
)
mark_as_advanced(
LATEX_COMPILER
PDFLATEX_COMPILER
BIBTEX_COMPILER
BIBER_COMPILER
MAKEINDEX_COMPILER
XINDY_COMPILER
DVIPS_CONVERTER
PS2PDF_CONVERTER
PDFTOPS_CONVERTER
LATEX2HTML_CONVERTER
HTLATEX_COMPILER
)
latex_needit(LATEX_COMPILER latex)
latex_wantit(PDFLATEX_COMPILER pdflatex)
latex_wantit(HTLATEX_COMPILER htlatex)
latex_needit(BIBTEX_COMPILER bibtex)
latex_wantit(BIBER_COMPILER biber)
latex_needit(MAKEINDEX_COMPILER makeindex)
latex_wantit(DVIPS_CONVERTER dvips)
latex_wantit(PS2PDF_CONVERTER ps2pdf)
latex_wantit(PDFTOPS_CONVERTER pdftops)
set(LATEX_COMPILER_FLAGS "-interaction=batchmode -file-line-error"
CACHE STRING "Flags passed to latex.")
set(PDFLATEX_COMPILER_FLAGS ${LATEX_COMPILER_FLAGS}
CACHE STRING "Flags passed to pdflatex.")
set(HTLATEX_COMPILER_TEX4HT_FLAGS "html"
CACHE STRING "Options for the tex4ht.sty and *.4ht style files.")
set(HTLATEX_COMPILER_TEX4HT_POSTPROCESSOR_FLAGS ""
CACHE STRING "Options for the text4ht postprocessor.")
set(HTLATEX_COMPILER_T4HT_POSTPROCESSOR_FLAGS ""
CACHE STRING "Options for the t4ht postprocessor.")
set(HTLATEX_COMPILER_LATEX_FLAGS ${LATEX_COMPILER_FLAGS}
CACHE STRING "Flags passed from htlatex to the LaTeX compiler.")
set(LATEX_SYNCTEX_FLAGS "-synctex=1"
CACHE STRING "latex/pdflatex flags used to create synctex file.")
set(BIBTEX_COMPILER_FLAGS ""
CACHE STRING "Flags passed to bibtex.")
set(BIBER_COMPILER_FLAGS ""
CACHE STRING "Flags passed to biber.")
set(MAKEINDEX_COMPILER_FLAGS ""
CACHE STRING "Flags passed to makeindex.")
set(MAKEGLOSSARIES_COMPILER_FLAGS ""
CACHE STRING "Flags passed to makeglossaries.")
set(MAKENOMENCLATURE_COMPILER_FLAGS ""
CACHE STRING "Flags passed to makenomenclature.")
set(DVIPS_CONVERTER_FLAGS "-Ppdf -G0 -t letter"
CACHE STRING "Flags passed to dvips.")
if(NOT WIN32)
set(PS2PDF_CONVERTER_FLAGS "-dMaxSubsetPct=100 -dCompatibilityLevel=1.3 -dSubsetFonts=true -dEmbedAllFonts=true -dAutoFilterColorImages=false -dAutoFilterGrayImages=false -dColorImageFilter=/FlateEncode -dGrayImageFilter=/FlateEncode -dMonoImageFilter=/FlateEncode"
CACHE STRING "Flags passed to ps2pdf.")
else()
# Most windows ports of ghostscript utilities use .bat files for ps2pdf
# commands. bat scripts interpret "=" as a special character and separate
# those arguments. To get around this, the ghostscript utilities also
# support using "#" in place of "=".
set(PS2PDF_CONVERTER_FLAGS "-dMaxSubsetPct#100 -dCompatibilityLevel#1.3 -dSubsetFonts#true -dEmbedAllFonts#true -dAutoFilterColorImages#false -dAutoFilterGrayImages#false -dColorImageFilter#/FlateEncode -dGrayImageFilter#/FlateEncode -dMonoImageFilter#/FlateEncode"
CACHE STRING "Flags passed to ps2pdf.")
endif()
set(PDFTOPS_CONVERTER_FLAGS ""
CACHE STRING "Flags passed to pdftops.")
mark_as_advanced(
LATEX_COMPILER_FLAGS
PDFLATEX_COMPILER_FLAGS
HTLATEX_COMPILER_TEX4HT_FLAGS
HTLATEX_COMPILER_TEX4HT_POSTPROCESSOR_FLAGS
HTLATEX_COMPILER_T4HT_POSTPROCESSOR_FLAGS
HTLATEX_COMPILER_LATEX_FLAGS
LATEX_SYNCTEX_FLAGS
BIBTEX_COMPILER_FLAGS
BIBER_COMPILER_FLAGS
MAKEINDEX_COMPILER_FLAGS
MAKEGLOSSARIES_COMPILER_FLAGS
MAKENOMENCLATURE_COMPILER_FLAGS
DVIPS_CONVERTER_FLAGS
PS2PDF_CONVERTER_FLAGS
PDFTOPS_CONVERTER_FLAGS
)
# Because it is easier to type, the flags variables are entered as
# space-separated strings much like you would in a shell. However, when
# using a CMake command to execute a program, it works better to hold the
# arguments in semicolon-separated lists (otherwise the whole string will
# be interpreted as a single argument). Use the separate_arguments to
# convert the space-separated strings to semicolon-separated lists.
separate_arguments(LATEX_COMPILER_FLAGS)
separate_arguments(PDFLATEX_COMPILER_FLAGS)
separate_arguments(HTLATEX_COMPILER_LATEX_FLAGS)
separate_arguments(LATEX_SYNCTEX_FLAGS)
separate_arguments(BIBTEX_COMPILER_FLAGS)
separate_arguments(BIBER_COMPILER_FLAGS)
separate_arguments(MAKEINDEX_COMPILER_FLAGS)
separate_arguments(MAKEGLOSSARIES_COMPILER_FLAGS)
separate_arguments(MAKENOMENCLATURE_COMPILER_FLAGS)
separate_arguments(DVIPS_CONVERTER_FLAGS)
separate_arguments(PS2PDF_CONVERTER_FLAGS)
separate_arguments(PDFTOPS_CONVERTER_FLAGS)
# Not quite done. When you call separate_arguments on a cache variable,
# the result is written to a local variable. That local variable goes
# away when this function returns (which is before any of them are used).
# So, copy these variables with local scope to cache variables with
# global scope.
set(LATEX_COMPILER_ARGS "${LATEX_COMPILER_FLAGS}" CACHE INTERNAL "")
set(PDFLATEX_COMPILER_ARGS "${PDFLATEX_COMPILER_FLAGS}" CACHE INTERNAL "")
set(HTLATEX_COMPILER_ARGS "${HTLATEX_COMPILER_LATEX_FLAGS}" CACHE INTERNAL "")
set(LATEX_SYNCTEX_ARGS "${LATEX_SYNCTEX_FLAGS}" CACHE INTERNAL "")
set(BIBTEX_COMPILER_ARGS "${BIBTEX_COMPILER_FLAGS}" CACHE INTERNAL "")
set(BIBER_COMPILER_ARGS "${BIBER_COMPILER_FLAGS}" CACHE INTERNAL "")
set(MAKEINDEX_COMPILER_ARGS "${MAKEINDEX_COMPILER_FLAGS}" CACHE INTERNAL "")
set(MAKEGLOSSARIES_COMPILER_ARGS "${MAKEGLOSSARIES_COMPILER_FLAGS}" CACHE INTERNAL "")
set(MAKENOMENCLATURE_COMPILER_ARGS "${MAKENOMENCLATURE_COMPILER_FLAGS}" CACHE INTERNAL "")
set(DVIPS_CONVERTER_ARGS "${DVIPS_CONVERTER_FLAGS}" CACHE INTERNAL "")
set(PS2PDF_CONVERTER_ARGS "${PS2PDF_CONVERTER_FLAGS}" CACHE INTERNAL "")
set(PDFTOPS_CONVERTER_ARGS "${PDFTOPS_CONVERTER_FLAGS}" CACHE INTERNAL "")
find_program(IMAGEMAGICK_CONVERT
NAMES magick convert
DOC "The convert program that comes with ImageMagick (available at http://www.imagemagick.org)."
)
mark_as_advanced(IMAGEMAGICK_CONVERT)
if(DEFINED ENV{LATEX_DEFAULT_BUILD})
set(default_build $ENV{LATEX_DEFAULT_BUILD})
else()
set(default_build pdf)
endif()
set(LATEX_DEFAULT_BUILD "${default_build}" CACHE STRING
"Choose the default type of LaTeX build. Valid options are pdf, dvi, ps, safepdf, html"
)
set_property(CACHE LATEX_DEFAULT_BUILD
PROPERTY STRINGS pdf dvi ps safepdf html
)
option(LATEX_USE_SYNCTEX
"If on, have LaTeX generate a synctex file, which WYSIWYG editors can use to correlate output files like dvi and pdf with the lines of LaTeX source that generates them. In addition to adding the LATEX_SYNCTEX_FLAGS to the command line, this option also adds build commands that \"corrects\" the resulting synctex file to point to the original LaTeX files rather than those generated by UseLATEX.cmake."
OFF
)
option(LATEX_SMALL_IMAGES
"If on, the raster images will be converted to 1/6 the original size. This is because papers usually require 600 dpi images whereas most monitors only require at most 96 dpi. Thus, smaller images make smaller files for web distribution and can make it faster to read dvi files."
OFF)
if(LATEX_SMALL_IMAGES)
set(LATEX_RASTER_SCALE 16 PARENT_SCOPE)
set(LATEX_OPPOSITE_RASTER_SCALE 100 PARENT_SCOPE)
else()
set(LATEX_RASTER_SCALE 100 PARENT_SCOPE)
set(LATEX_OPPOSITE_RASTER_SCALE 16 PARENT_SCOPE)
endif()
# Just holds extensions for known image types. They should all be lower case.
# For historical reasons, these are all declared in the global scope.
set(LATEX_DVI_VECTOR_IMAGE_EXTENSIONS .eps CACHE INTERNAL "")
set(LATEX_DVI_RASTER_IMAGE_EXTENSIONS CACHE INTERNAL "")
set(LATEX_DVI_IMAGE_EXTENSIONS
${LATEX_DVI_VECTOR_IMAGE_EXTENSIONS}
${LATEX_DVI_RASTER_IMAGE_EXTENSIONS}
CACHE INTERNAL ""
)
set(LATEX_PDF_VECTOR_IMAGE_EXTENSIONS .pdf CACHE INTERNAL "")
set(LATEX_PDF_RASTER_IMAGE_EXTENSIONS .jpeg .jpg .png CACHE INTERNAL "")
set(LATEX_PDF_IMAGE_EXTENSIONS
${LATEX_PDF_VECTOR_IMAGE_EXTENSIONS}
${LATEX_PDF_RASTER_IMAGE_EXTENSIONS}
CACHE INTERNAL ""
)
set(LATEX_OTHER_VECTOR_IMAGE_EXTENSIONS .ai .dot .svg CACHE INTERNAL "")
set(LATEX_OTHER_RASTER_IMAGE_EXTENSIONS
.bmp .bmp2 .bmp3 .dcm .dcx .ico .gif .pict .ppm .tif .tiff
CACHE INTERNAL "")
set(LATEX_OTHER_IMAGE_EXTENSIONS
${LATEX_OTHER_VECTOR_IMAGE_EXTENSIONS}
${LATEX_OTHER_RASTER_IMAGE_EXTENSIONS}
CACHE INTERNAL ""
)
set(LATEX_VECTOR_IMAGE_EXTENSIONS
${LATEX_DVI_VECTOR_IMAGE_EXTENSIONS}
${LATEX_PDF_VECTOR_IMAGE_EXTENSIONS}
${LATEX_OTHER_VECTOR_IMAGE_EXTENSIONS}
CACHE INTERNAL ""
)
set(LATEX_RASTER_IMAGE_EXTENSIONS
${LATEX_DVI_RASTER_IMAGE_EXTENSIONS}
${LATEX_PDF_RASTER_IMAGE_EXTENSIONS}
${LATEX_OTHER_RASTER_IMAGE_EXTENSIONS}
CACHE INTERNAL ""
)
set(LATEX_IMAGE_EXTENSIONS
${LATEX_DVI_IMAGE_EXTENSIONS}
${LATEX_PDF_IMAGE_EXTENSIONS}
${LATEX_OTHER_IMAGE_EXTENSIONS}
CACHE INTERNAL ""
)
endfunction(latex_setup_variables)
function(latex_setup_targets)
if(NOT TARGET pdf)
add_custom_target(pdf)
endif()
if(NOT TARGET dvi)
add_custom_target(dvi)
endif()
if(NOT TARGET ps)
add_custom_target(ps)
endif()
if(NOT TARGET safepdf)
add_custom_target(safepdf)
endif()
if(NOT TARGET html)
add_custom_target(html)
endif()
if(NOT TARGET auxclean)
add_custom_target(auxclean)
endif()
endfunction(latex_setup_targets)
function(latex_get_output_path var)
set(latex_output_path)
if(LATEX_OUTPUT_PATH)
get_filename_component(
LATEX_OUTPUT_PATH_FULL "${LATEX_OUTPUT_PATH}" ABSOLUTE
)
if("${LATEX_OUTPUT_PATH_FULL}" STREQUAL "${CMAKE_CURRENT_SOURCE_DIR}")
message(SEND_ERROR "You cannot set LATEX_OUTPUT_PATH to the same directory that contains LaTeX input files.")
else()
set(latex_output_path "${LATEX_OUTPUT_PATH_FULL}")
endif()
else()
if("${CMAKE_CURRENT_BINARY_DIR}" STREQUAL "${CMAKE_CURRENT_SOURCE_DIR}")
message(SEND_ERROR "LaTeX files must be built out of source or you must set LATEX_OUTPUT_PATH.")
else()
set(latex_output_path "${CMAKE_CURRENT_BINARY_DIR}")
endif()
endif()
set(${var} ${latex_output_path} PARENT_SCOPE)
endfunction(latex_get_output_path)
function(latex_add_convert_command
output_path
input_path
output_extension
input_extension
flags
)
set(require_imagemagick_convert TRUE)
set(convert_flags "")
if(${input_extension} STREQUAL ".eps" AND ${output_extension} STREQUAL ".pdf")
# ImageMagick has broken eps to pdf conversion
# use ps2pdf instead
if(PS2PDF_CONVERTER)
set(require_imagemagick_convert FALSE)
set(converter ${PS2PDF_CONVERTER})
set(convert_flags -dEPSCrop ${PS2PDF_CONVERTER_ARGS})
else()
message(SEND_ERROR "Using postscript files with pdflatex requires ps2pdf for conversion.")
endif()
elseif(${input_extension} STREQUAL ".pdf" AND ${output_extension} STREQUAL ".eps")
# ImageMagick can also be sketchy on pdf to eps conversion. Not good with
# color spaces and tends to unnecessarily rasterize.
# use pdftops instead
if(PDFTOPS_CONVERTER)
set(require_imagemagick_convert FALSE)
set(converter ${PDFTOPS_CONVERTER})
set(convert_flags -eps ${PDFTOPS_CONVERTER_ARGS})
else()
message(STATUS "Consider getting pdftops from Poppler to convert PDF images to EPS images.")
set(convert_flags ${flags})
endif()
else()
set(convert_flags ${flags})
endif()
if(require_imagemagick_convert)
if(IMAGEMAGICK_CONVERT)
string(TOLOWER ${IMAGEMAGICK_CONVERT} IMAGEMAGICK_CONVERT_LOWERCASE)
if(${IMAGEMAGICK_CONVERT_LOWERCASE} MATCHES "system32[/\\\\]convert\\.exe")
message(SEND_ERROR "IMAGEMAGICK_CONVERT set to Window's convert.exe for changing file systems rather than ImageMagick's convert for changing image formats. Please make sure ImageMagick is installed (available at http://www.imagemagick.org). If you have a recent version of ImageMagick (7.0 or higher), use the magick program instead of convert for IMAGEMAGICK_CONVERT.")
else()
set(converter ${IMAGEMAGICK_CONVERT})
# ImageMagick requires a special order of arguments where resize and
# arguments of that nature must be placed after the input image path.
add_custom_command(OUTPUT ${output_path}
COMMAND ${converter}
ARGS ${input_path} ${convert_flags} ${output_path}
DEPENDS ${input_path}
)
endif()
else()
message(SEND_ERROR "Could not find convert program. Please download ImageMagick from http://www.imagemagick.org and install.")
endif()
else() # Not ImageMagick convert
add_custom_command(OUTPUT ${output_path}
COMMAND ${converter}
ARGS ${convert_flags} ${input_path} ${output_path}
DEPENDS ${input_path}
)
endif()
endfunction(latex_add_convert_command)
# Makes custom commands to convert a file to a particular type.
function(latex_convert_image
output_files_var
input_file
output_extension
convert_flags
output_extensions
other_files
)
set(output_file_list)
set(input_dir ${CMAKE_CURRENT_SOURCE_DIR})
latex_get_output_path(output_dir)
latex_get_filename_component(extension "${input_file}" EXT)
# Check input filename for potential problems with LaTeX.
latex_get_filename_component(name "${input_file}" NAME_WE)
set(suggested_name "${name}")
if(suggested_name MATCHES ".*\\..*")
string(REPLACE "." "-" suggested_name "${suggested_name}")
endif()
if(suggested_name MATCHES ".* .*")
string(REPLACE " " "-" suggested_name "${suggested_name}")
endif()
if(NOT suggested_name STREQUAL name)
message(WARNING "Some LaTeX distributions have problems with image file names with multiple extensions or spaces. Consider changing ${name}${extension} to something like ${suggested_name}${extension}.")
endif()
string(REGEX REPLACE "\\.[^.]*\$" ${output_extension} output_file
"${input_file}")
latex_list_contains(is_type ${extension} ${output_extensions})
if(is_type)
if(convert_flags)
latex_add_convert_command(${output_dir}/${output_file}
${input_dir}/${input_file} ${output_extension} ${extension}
"${convert_flags}")
set(output_file_list ${output_dir}/${output_file})
else()
# As a shortcut, we can just copy the file.
add_custom_command(OUTPUT ${output_dir}/${input_file}
COMMAND ${CMAKE_COMMAND}
ARGS -E copy ${input_dir}/${input_file} ${output_dir}/${input_file}
DEPENDS ${input_dir}/${input_file}
)
set(output_file_list ${output_dir}/${input_file})
endif()
else()
set(do_convert TRUE)
# Check to see if there is another input file of the appropriate type.
foreach(valid_extension ${output_extensions})
string(REGEX REPLACE "\\.[^.]*\$" ${output_extension} try_file
"${input_file}")
latex_list_contains(has_native_file "${try_file}" ${other_files})
if(has_native_file)
set(do_convert FALSE)
endif()
endforeach(valid_extension)
# If we still need to convert, do it.
if(do_convert)
latex_add_convert_command(${output_dir}/${output_file}
${input_dir}/${input_file} ${output_extension} ${extension}
"${convert_flags}")
set(output_file_list ${output_dir}/${output_file})
endif()
endif()
set(${output_files_var} ${output_file_list} PARENT_SCOPE)
endfunction(latex_convert_image)
# Adds custom commands to process the given files for dvi and pdf builds.
# Adds the output files to the given variables (does not replace).
function(latex_process_images dvi_outputs_var pdf_outputs_var)
latex_get_output_path(output_dir)
set(dvi_outputs)
set(pdf_outputs)
foreach(file ${ARGN})
if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${file}")
latex_get_filename_component(extension "${file}" EXT)
set(convert_flags)
# Check to see if we need to downsample the image.
latex_list_contains(is_raster "${extension}"
${LATEX_RASTER_IMAGE_EXTENSIONS})
if(LATEX_SMALL_IMAGES)
if(is_raster)
set(convert_flags -resize ${LATEX_RASTER_SCALE}%)
endif()
endif()
# Make sure the output directory exists.
latex_get_filename_component(path "${output_dir}/${file}" PATH)
make_directory("${path}")
latex_convert_image(output_files "${file}" .pdf "${convert_flags}"
"${LATEX_PDF_IMAGE_EXTENSIONS}" "${ARGN}")
list(APPEND pdf_outputs ${output_files})
else()
message(WARNING "Could not find file ${CMAKE_CURRENT_SOURCE_DIR}/${file}. Are you sure you gave relative paths to IMAGES?")
endif()
endforeach(file)
set(${dvi_outputs_var} ${dvi_outputs} PARENT_SCOPE)
set(${pdf_outputs_var} ${pdf_outputs} PARENT_SCOPE)
endfunction(latex_process_images)
function(latex_copy_globbed_files pattern dest)
file(GLOB file_list ${pattern})
foreach(in_file ${file_list})
latex_get_filename_component(out_file ${in_file} NAME)
configure_file(${in_file} ${dest}/${out_file} COPYONLY)
endforeach(in_file)
endfunction(latex_copy_globbed_files)
function(latex_copy_input_file file)
latex_get_output_path(output_dir)
if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${file})
latex_get_filename_component(path ${file} PATH)
file(MAKE_DIRECTORY ${output_dir}/${path})
latex_list_contains(use_config ${file} ${LATEX_CONFIGURE})
if(use_config)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/${file}
${output_dir}/${file}
@ONLY
)
add_custom_command(OUTPUT ${output_dir}/${file}
COMMAND ${CMAKE_COMMAND}
ARGS ${CMAKE_BINARY_DIR}
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${file}
)
else()
add_custom_command(OUTPUT ${output_dir}/${file}
COMMAND ${CMAKE_COMMAND}
ARGS -E copy ${CMAKE_CURRENT_SOURCE_DIR}/${file} ${output_dir}/${file}
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${file}
)
endif()
else()
if(EXISTS ${output_dir}/${file})
# Special case: output exists but input does not. Assume that it was
# created elsewhere and skip the input file copy.
else()
message("Could not find input file ${CMAKE_CURRENT_SOURCE_DIR}/${file}")
endif()
endif()
endfunction(latex_copy_input_file)
#############################################################################
# Commands provided by the UseLATEX.cmake "package"
#############################################################################
function(latex_usage command message)
message(SEND_ERROR
"${message}\n Usage: ${command}(<tex_file>\n [BIBFILES <bib_file> <bib_file> ...]\n [INPUTS <tex_file> <tex_file> ...]\n [IMAGE_DIRS <directory1> <directory2> ...]\n [IMAGES <image_file1> <image_file2>\n [CONFIGURE <tex_file> <tex_file> ...]\n [DEPENDS <tex_file> <tex_file> ...]\n [MULTIBIB_NEWCITES] <suffix_list>\n [USE_BIBLATEX] [USE_INDEX] [USE_GLOSSARY] [USE_NOMENCL]\n [FORCE_PDF] [FORCE_DVI] [FORCE_HTML]\n [TARGET_NAME] <name>\n [EXCLUDE_FROM_ALL]\n [EXCLUDE_FROM_DEFAULTS])"
)
endfunction(latex_usage command message)
# Parses arguments to add_latex_document and ADD_LATEX_TARGETS and sets the
# variables LATEX_TARGET, LATEX_IMAGE_DIR, LATEX_BIBFILES, LATEX_DEPENDS, and
# LATEX_INPUTS.
function(parse_add_latex_arguments command latex_main_input)
set(options
USE_BIBLATEX
USE_INDEX
USE_GLOSSARY
USE_NOMENCL
FORCE_PDF
FORCE_DVI
FORCE_HTML
EXCLUDE_FROM_ALL
EXCLUDE_FROM_DEFAULTS
# Deprecated options
USE_GLOSSARIES
DEFAULT_PDF
DEFAULT_SAFEPDF
DEFAULT_PS
NO_DEFAULT
MANGLE_TARGET_NAMES
)
set(oneValueArgs
TARGET_NAME
)
set(multiValueArgs
BIBFILES
MULTIBIB_NEWCITES
INPUTS
IMAGE_DIRS
IMAGES
CONFIGURE
DEPENDS
INDEX_NAMES
)
cmake_parse_arguments(
LATEX "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
# Handle invalid and deprecated arguments
if(LATEX_UNPARSED_ARGUMENTS)
latex_usage(${command} "Invalid or deprecated arguments: ${LATEX_UNPARSED_ARGUMENTS}")
endif()
if(LATEX_USE_GLOSSARIES)
latex_usage(${command} "USE_GLOSSARIES option removed in version 1.6.1. Use USE_GLOSSARY instead.")
endif()
if(LATEX_DEFAULT_PDF)
latex_usage(${command} "DEFAULT_PDF option removed in version 2.0. Use FORCE_PDF option or LATEX_DEFAULT_BUILD CMake variable instead.")
endif()
if(LATEX_DEFAULT_SAFEPDF)
latex_usage(${command} "DEFAULT_SAFEPDF option removed in version 2.0. Use LATEX_DEFAULT_BUILD CMake variable instead.")
endif()
if(LATEX_DEFAULT_DVI)
latex_usage(${command} "DEFAULT_DVI option removed in version 2.0. Use FORCE_DVI option or LATEX_DEFAULT_BUILD CMake variable instead.")
endif()
if(LATEX_NO_DEFAULT)
latex_usage(${command} "NO_DEFAULT option removed in version 2.0. Use EXCLUDE_FROM_ALL instead.")
endif()
if(LATEX_MANGLE_TARGET_NAMES)
latex_usage(${command} "MANGLE_TARGET_NAMES option removed in version 2.0. All LaTeX targets use mangled names now.")
endif()
# Capture the first argument, which is the main LaTeX input.
latex_get_filename_component(latex_target ${latex_main_input} NAME_WE)
set(LATEX_MAIN_INPUT ${latex_main_input} PARENT_SCOPE)
set(LATEX_TARGET ${latex_target} PARENT_SCOPE)
# Propagate the result variables to the caller
foreach(arg_name ${options} ${oneValueArgs} ${multiValueArgs})
set(var_name LATEX_${arg_name})
set(${var_name} ${${var_name}} PARENT_SCOPE)
endforeach(arg_name)
endfunction(parse_add_latex_arguments)
function(add_latex_targets_internal)
latex_get_output_path(output_dir)
if(LATEX_USE_SYNCTEX)
set(synctex_flags ${LATEX_SYNCTEX_ARGS})
else()
set(synctex_flags)
endif()
# The commands to run LaTeX. They are repeated multiple times.
set(latex_build_command
${LATEX_COMPILER} ${LATEX_COMPILER_ARGS} ${synctex_flags} ${LATEX_MAIN_INPUT}
)
if(LATEX_COMPILER_ARGS MATCHES ".*batchmode.*")
# Wrap command in script that dumps the log file on error. This makes sure
# errors can be seen.
set(latex_build_command
${CMAKE_COMMAND}
-D LATEX_BUILD_COMMAND=execute_latex
-D LATEX_TARGET=${LATEX_TARGET}
-D LATEX_WORKING_DIRECTORY="${output_dir}"
-D LATEX_FULL_COMMAND="${latex_build_command}"
-D LATEX_OUTPUT_FILE="${LATEX_TARGET}.dvi"
-P "${LATEX_USE_LATEX_LOCATION}"
)
endif()
set(pdflatex_build_command
${PDFLATEX_COMPILER} ${PDFLATEX_COMPILER_ARGS} ${synctex_flags} ${LATEX_MAIN_INPUT}
)
if(PDFLATEX_COMPILER_ARGS MATCHES ".*batchmode.*")
# Wrap command in script that dumps the log file on error. This makes sure
# errors can be seen.
set(pdflatex_build_command
${CMAKE_COMMAND}
-D LATEX_BUILD_COMMAND=execute_latex
-D LATEX_TARGET=${LATEX_TARGET}
-D LATEX_WORKING_DIRECTORY="${output_dir}"
-D LATEX_FULL_COMMAND="${pdflatex_build_command}"
-D LATEX_OUTPUT_FILE="${LATEX_TARGET}.pdf"
-P "${LATEX_USE_LATEX_LOCATION}"
)
endif()
if(NOT LATEX_TARGET_NAME)
# Use the main filename (minus the .tex) as the target name. Remove any
# spaces since CMake cannot have spaces in its target names.
string(REPLACE " " "_" LATEX_TARGET_NAME ${LATEX_TARGET})
endif()
# Some LaTeX commands may need to be modified (or may not work) if the main
# tex file is in a subdirectory. Make a flag for that.
get_filename_component(LATEX_MAIN_INPUT_SUBDIR ${LATEX_MAIN_INPUT} DIRECTORY)
# Set up target names.
set(dvi_target ${LATEX_TARGET_NAME}_dvi)
set(pdf_target ${LATEX_TARGET_NAME}_pdf)
set(ps_target ${LATEX_TARGET_NAME}_ps)
set(safepdf_target ${LATEX_TARGET_NAME}_safepdf)
set(html_target ${LATEX_TARGET_NAME}_html)
set(auxclean_target ${LATEX_TARGET_NAME}_auxclean)
# Probably not all of these will be generated, but they could be.
# Note that the aux file is added later.
set(auxiliary_clean_files
${output_dir}/${LATEX_TARGET}.aux
${output_dir}/${LATEX_TARGET}.bbl
${output_dir}/${LATEX_TARGET}.blg
${output_dir}/${LATEX_TARGET}-blx.bib
${output_dir}/${LATEX_TARGET}.glg
${output_dir}/${LATEX_TARGET}.glo
${output_dir}/${LATEX_TARGET}.gls
${output_dir}/${LATEX_TARGET}.idx
${output_dir}/${LATEX_TARGET}.ilg
${output_dir}/${LATEX_TARGET}.ind
${output_dir}/${LATEX_TARGET}.ist
${output_dir}/${LATEX_TARGET}.log
${output_dir}/${LATEX_TARGET}.out
${output_dir}/${LATEX_TARGET}.toc
${output_dir}/${LATEX_TARGET}.lof
${output_dir}/${LATEX_TARGET}.xdy
${output_dir}/${LATEX_TARGET}.synctex.gz
${output_dir}/${LATEX_TARGET}.synctex.bak.gz
${output_dir}/${LATEX_TARGET}.dvi
${output_dir}/${LATEX_TARGET}.ps
${output_dir}/${LATEX_TARGET}.pdf
)
set(image_list ${LATEX_IMAGES})
# For each directory in LATEX_IMAGE_DIRS, glob all the image files and
# place them in LATEX_IMAGES.
foreach(dir ${LATEX_IMAGE_DIRS})
if(NOT EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${dir})
message(WARNING "Image directory ${CMAKE_CURRENT_SOURCE_DIR}/${dir} does not exist. Are you sure you gave relative directories to IMAGE_DIRS?")
endif()
foreach(extension ${LATEX_IMAGE_EXTENSIONS})
file(GLOB files ${CMAKE_CURRENT_SOURCE_DIR}/${dir}/*${extension})
foreach(file ${files})
latex_get_filename_component(filename ${file} NAME)
list(APPEND image_list ${dir}/${filename})
endforeach(file)
endforeach(extension)
endforeach(dir)
latex_process_images(dvi_images pdf_images ${image_list})
set(make_dvi_command
${CMAKE_COMMAND} -E chdir ${output_dir}
${latex_build_command})
set(make_pdf_command
${CMAKE_COMMAND} -E chdir ${output_dir}
${pdflatex_build_command}
)
set(make_dvi_depends ${LATEX_DEPENDS} ${dvi_images})
set(make_pdf_depends ${LATEX_DEPENDS} ${pdf_images})
foreach(input ${LATEX_MAIN_INPUT} ${LATEX_INPUTS})
list(APPEND make_dvi_depends ${output_dir}/${input})
list(APPEND make_pdf_depends ${output_dir}/${input})
if(${input} MATCHES "\\.tex$")
# Dependent .tex files might have their own .aux files created. Make
# sure these get cleaned as well. This might replicate the cleaning
# of the main .aux file, which is OK.
string(REGEX REPLACE "\\.tex$" "" input_we ${input})
list(APPEND auxiliary_clean_files
${output_dir}/${input_we}.aux
${output_dir}/${input}.aux
)
endif()
endforeach(input)
set(all_latex_sources ${LATEX_MAIN_INPUT} ${LATEX_INPUTS} ${image_list})
if(LATEX_USE_GLOSSARY)
foreach(dummy 0 1) # Repeat these commands twice.
set(make_dvi_command ${make_dvi_command}
COMMAND ${CMAKE_COMMAND} -E chdir ${output_dir}
${CMAKE_COMMAND}
-D LATEX_BUILD_COMMAND=makeglossaries
-D LATEX_TARGET=${LATEX_TARGET}
-D MAKEINDEX_COMPILER=${MAKEINDEX_COMPILER}
-D XINDY_COMPILER=${XINDY_COMPILER}
-D MAKEGLOSSARIES_COMPILER_ARGS=${MAKEGLOSSARIES_COMPILER_ARGS}
-P ${LATEX_USE_LATEX_LOCATION}
COMMAND ${CMAKE_COMMAND} -E chdir ${output_dir}
${latex_build_command}
)
set(make_pdf_command ${make_pdf_command}
COMMAND ${CMAKE_COMMAND} -E chdir ${output_dir}
${CMAKE_COMMAND}
-D LATEX_BUILD_COMMAND=makeglossaries
-D LATEX_TARGET=${LATEX_TARGET}
-D MAKEINDEX_COMPILER=${MAKEINDEX_COMPILER}
-D XINDY_COMPILER=${XINDY_COMPILER}
-D MAKEGLOSSARIES_COMPILER_ARGS=${MAKEGLOSSARIES_COMPILER_ARGS}
-P ${LATEX_USE_LATEX_LOCATION}
COMMAND ${CMAKE_COMMAND} -E chdir ${output_dir}
${pdflatex_build_command}
)
endforeach(dummy)
endif()
if(LATEX_USE_NOMENCL)
foreach(dummy 0 1) # Repeat these commands twice.
set(make_dvi_command ${make_dvi_command}
COMMAND ${CMAKE_COMMAND} -E chdir ${output_dir}
${CMAKE_COMMAND}
-D LATEX_BUILD_COMMAND=makenomenclature
-D LATEX_TARGET=${LATEX_TARGET}
-D MAKEINDEX_COMPILER=${MAKEINDEX_COMPILER}
-D MAKENOMENCLATURE_COMPILER_ARGS=${MAKENOMENCLATURE_COMPILER_ARGS}
-P ${LATEX_USE_LATEX_LOCATION}
COMMAND ${CMAKE_COMMAND} -E chdir ${output_dir}
${latex_build_command}
)
set(make_pdf_command ${make_pdf_command}
COMMAND ${CMAKE_COMMAND} -E chdir ${output_dir}
${CMAKE_COMMAND}
-D LATEX_BUILD_COMMAND=makenomenclature
-D LATEX_TARGET=${LATEX_TARGET}
-D MAKEINDEX_COMPILER=${MAKEINDEX_COMPILER}
-D MAKENOMENCLATURE_COMPILER_ARGS=${MAKENOMENCLATURE_COMPILER_ARGS}
-P ${LATEX_USE_LATEX_LOCATION}
COMMAND ${CMAKE_COMMAND} -E chdir ${output_dir}
${pdflatex_build_command}
)
endforeach(dummy)
endif()
if(LATEX_BIBFILES)
if(LATEX_USE_BIBLATEX)
if(NOT BIBER_COMPILER)
message(SEND_ERROR "I need the biber command.")
endif()
set(bib_compiler ${BIBER_COMPILER})
set(bib_compiler_flags ${BIBER_COMPILER_ARGS})
else()
set(bib_compiler ${BIBTEX_COMPILER})
set(bib_compiler_flags ${BIBTEX_COMPILER_ARGS})
endif()
if(LATEX_MULTIBIB_NEWCITES)
foreach (multibib_auxfile ${LATEX_MULTIBIB_NEWCITES})
latex_get_filename_component(multibib_target ${multibib_auxfile} NAME_WE)
set(make_dvi_command ${make_dvi_command}
COMMAND ${CMAKE_COMMAND} -E chdir ${output_dir}
${bib_compiler} ${bib_compiler_flags} ${multibib_target})
set(make_pdf_command ${make_pdf_command}
COMMAND ${CMAKE_COMMAND} -E chdir ${output_dir}
${bib_compiler} ${bib_compiler_flags} ${multibib_target})
set(auxiliary_clean_files ${auxiliary_clean_files}
${output_dir}/${multibib_target}.aux)
endforeach (multibib_auxfile ${LATEX_MULTIBIB_NEWCITES})
else()
set(make_dvi_command ${make_dvi_command}
COMMAND ${CMAKE_COMMAND} -E chdir ${output_dir}
${bib_compiler} ${bib_compiler_flags} ${LATEX_TARGET})
set(make_pdf_command ${make_pdf_command}
COMMAND ${CMAKE_COMMAND} -E chdir ${output_dir}
${bib_compiler} ${bib_compiler_flags} ${LATEX_TARGET})
endif()
foreach (bibfile ${LATEX_BIBFILES})
list(APPEND make_dvi_depends ${output_dir}/${bibfile})
list(APPEND make_pdf_depends ${output_dir}/${bibfile})
endforeach (bibfile ${LATEX_BIBFILES})
else()
if(LATEX_MULTIBIB_NEWCITES)
message(WARNING "MULTIBIB_NEWCITES has no effect without BIBFILES option.")
endif()
endif()
if(LATEX_USE_INDEX)
if(LATEX_INDEX_NAMES)
set(INDEX_NAMES ${LATEX_INDEX_NAMES})
else()
set(INDEX_NAMES ${LATEX_TARGET})
endif()
foreach(idx_name ${INDEX_NAMES})
set(make_dvi_command ${make_dvi_command}
COMMAND ${CMAKE_COMMAND} -E chdir ${output_dir}
${latex_build_command}
COMMAND ${CMAKE_COMMAND} -E chdir ${output_dir}
${MAKEINDEX_COMPILER} ${MAKEINDEX_COMPILER_ARGS} ${idx_name}.idx)
set(make_pdf_command ${make_pdf_command}
COMMAND ${CMAKE_COMMAND} -E chdir ${output_dir}
${pdflatex_build_command}
COMMAND ${CMAKE_COMMAND} -E chdir ${output_dir}
${MAKEINDEX_COMPILER} ${MAKEINDEX_COMPILER_ARGS} ${idx_name}.idx)
set(auxiliary_clean_files ${auxiliary_clean_files}
${output_dir}/${idx_name}.idx
${output_dir}/${idx_name}.ilg
${output_dir}/${idx_name}.ind)
endforeach()
else()
if(LATEX_INDEX_NAMES)
message(WARNING "INDEX_NAMES has no effect without USE_INDEX option.")
endif()
endif()
set(make_dvi_command ${make_dvi_command}
COMMAND ${CMAKE_COMMAND} -E chdir ${output_dir}
${latex_build_command}
COMMAND ${CMAKE_COMMAND} -E chdir ${output_dir}
${latex_build_command})
set(make_pdf_command ${make_pdf_command}
COMMAND ${CMAKE_COMMAND} -E chdir ${output_dir}
${pdflatex_build_command}
COMMAND ${CMAKE_COMMAND} -E chdir ${output_dir}
${pdflatex_build_command})
# Need to run one more time to remove biblatex' warning
# about page breaks that have changed.
if(LATEX_USE_BIBLATEX)
set(make_dvi_command ${make_dvi_command}
COMMAND ${CMAKE_COMMAND} -E chdir ${output_dir}
${latex_build_command})
set(make_pdf_command ${make_pdf_command}
COMMAND ${CMAKE_COMMAND} -E chdir ${output_dir}
${pdflatex_build_command})
endif()
if(LATEX_USE_SYNCTEX)
if(NOT GZIP)
message(SEND_ERROR "UseLATEX.cmake: USE_SYNTEX option requires gzip program. Set GZIP variable.")
endif()
set(make_dvi_command ${make_dvi_command}
COMMAND ${CMAKE_COMMAND}
-D LATEX_BUILD_COMMAND=correct_synctex
-D LATEX_TARGET=${LATEX_TARGET}
-D GZIP=${GZIP}
-D "LATEX_SOURCE_DIRECTORY=${CMAKE_CURRENT_SOURCE_DIR}"
-D "LATEX_BINARY_DIRECTORY=${output_dir}"
-P ${LATEX_USE_LATEX_LOCATION}
)
set(make_pdf_command ${make_pdf_command}
COMMAND ${CMAKE_COMMAND}
-D LATEX_BUILD_COMMAND=correct_synctex
-D LATEX_TARGET=${LATEX_TARGET}
-D GZIP=${GZIP}
-D "LATEX_SOURCE_DIRECTORY=${CMAKE_CURRENT_SOURCE_DIR}"
-D "LATEX_BINARY_DIRECTORY=${output_dir}"
-P ${LATEX_USE_LATEX_LOCATION}
)
endif()
# Check LaTeX output for important warnings at end of build
set(make_dvi_command ${make_dvi_command}
COMMAND ${CMAKE_COMMAND} -E chdir ${output_dir}
${CMAKE_COMMAND}
-D LATEX_BUILD_COMMAND=check_important_warnings
-D LATEX_TARGET=${LATEX_TARGET}
-P ${LATEX_USE_LATEX_LOCATION}
)
set(make_pdf_command ${make_pdf_command}
COMMAND ${CMAKE_COMMAND} -E chdir ${output_dir}
${CMAKE_COMMAND}
-D LATEX_BUILD_COMMAND=check_important_warnings
-D LATEX_TARGET=${LATEX_TARGET}
-P ${LATEX_USE_LATEX_LOCATION}
)
# Capture the default build.
string(TOLOWER "${LATEX_DEFAULT_BUILD}" default_build)
if((NOT LATEX_FORCE_PDF) AND (NOT LATEX_FORCE_DVI) AND (NOT LATEX_FORCE_HTML))
set(no_force TRUE)
endif()
# Add commands and targets for building pdf outputs (with pdflatex).
if(LATEX_FORCE_PDF OR no_force)
if(LATEX_FORCE_PDF)
set(default_build pdf)
endif()
if(PDFLATEX_COMPILER)
add_custom_command(OUTPUT ${output_dir}/${LATEX_TARGET}.pdf
COMMAND ${make_pdf_command}
DEPENDS ${make_pdf_depends}
)
add_custom_target(${pdf_target}
DEPENDS ${output_dir}/${LATEX_TARGET}.pdf
SOURCES ${all_latex_sources}
)
if(NOT LATEX_EXCLUDE_FROM_DEFAULTS)
add_dependencies(pdf ${pdf_target})
endif()
endif()
endif()
# Add commands and targets for building dvi outputs.
if(LATEX_FORCE_DVI OR LATEX_FORCE_HTML OR no_force)
if(LATEX_FORCE_DVI)
if((NOT default_build STREQUAL dvi) AND
(NOT default_build STREQUAL ps) AND
(NOT default_build STREQUAL safepdf))
set(default_build dvi)
endif()
endif()
add_custom_command(OUTPUT ${output_dir}/${LATEX_TARGET}.dvi
COMMAND ${make_dvi_command}
DEPENDS ${make_dvi_depends}
)
add_custom_target(${dvi_target}
DEPENDS ${output_dir}/${LATEX_TARGET}.dvi
SOURCES ${all_latex_sources}
)
if(NOT LATEX_EXCLUDE_FROM_DEFAULTS)
add_dependencies(dvi ${dvi_target})
endif()
if(DVIPS_CONVERTER)
add_custom_command(OUTPUT ${output_dir}/${LATEX_TARGET}.ps
COMMAND ${CMAKE_COMMAND} -E chdir ${output_dir}
${DVIPS_CONVERTER} ${DVIPS_CONVERTER_ARGS} -o ${LATEX_TARGET}.ps ${LATEX_TARGET}.dvi
DEPENDS ${output_dir}/${LATEX_TARGET}.dvi)
add_custom_target(${ps_target}
DEPENDS ${output_dir}/${LATEX_TARGET}.ps
SOURCES ${all_latex_sources}
)
if(NOT LATEX_EXCLUDE_FROM_DEFAULTS)
add_dependencies(ps ${ps_target})
endif()
if(PS2PDF_CONVERTER)
# Since both the pdf and safepdf targets have the same output, we
# cannot properly do the dependencies for both. When selecting safepdf,
# simply force a recompile every time.
add_custom_target(${safepdf_target}
${CMAKE_COMMAND} -E chdir ${output_dir}
${PS2PDF_CONVERTER} ${PS2PDF_CONVERTER_ARGS} ${LATEX_TARGET}.ps ${LATEX_TARGET}.pdf
DEPENDS ${ps_target}
)
if(NOT LATEX_EXCLUDE_FROM_DEFAULTS)
add_dependencies(safepdf ${safepdf_target})
endif()
endif()
endif()
endif()
if(LATEX_FORCE_HTML OR no_force)
if (LATEX_FORCE_HTML)
set(default_build html)
endif()
if(HTLATEX_COMPILER AND LATEX_MAIN_INPUT_SUBDIR)
message(STATUS
"Disabling HTML build for ${LATEX_TARGET_NAME}.tex because the main file is in subdirectory ${LATEX_MAIN_INPUT_SUBDIR}"
)
# The code below to run HTML assumes that LATEX_TARGET.tex is in the
# current directory. I have tried to specify that LATEX_TARGET.tex is
# in a subdirectory. That makes the build targets correct, but the
# HTML build still fails (at least for htlatex) because files are not
# generated where expected. I am getting around the problem by simply
# disabling HTML in this case. If someone really cares, they can fix
# this, but make sure it runs on many platforms and build programs.
elseif(HTLATEX_COMPILER)
# htlatex places the output in a different location
set(HTML_OUTPUT "${output_dir}/${LATEX_TARGET}.html")
add_custom_command(OUTPUT ${HTML_OUTPUT}
COMMAND ${CMAKE_COMMAND} -E chdir ${output_dir}
${HTLATEX_COMPILER} ${LATEX_MAIN_INPUT}
"${HTLATEX_COMPILER_TEX4HT_FLAGS}"
"${HTLATEX_COMPILER_TEX4HT_POSTPROCESSOR_FLAGS}"
"${HTLATEX_COMPILER_T4HT_POSTPROCESSOR_FLAGS}"
${HTLATEX_COMPILER_ARGS}
DEPENDS
${output_dir}/${LATEX_TARGET}.tex
${output_dir}/${LATEX_TARGET}.dvi
VERBATIM
)
add_custom_target(${html_target}
DEPENDS ${HTML_OUTPUT} ${dvi_target}
SOURCES ${all_latex_sources}
)
if(NOT LATEX_EXCLUDE_FROM_DEFAULTS)
add_dependencies(html ${html_target})
endif()
endif()
endif()
# Set default targets.
if("${default_build}" STREQUAL "pdf")
add_custom_target(${LATEX_TARGET_NAME} DEPENDS ${pdf_target})
elseif("${default_build}" STREQUAL "dvi")
add_custom_target(${LATEX_TARGET_NAME} DEPENDS ${dvi_target})
elseif("${default_build}" STREQUAL "ps")
add_custom_target(${LATEX_TARGET_NAME} DEPENDS ${ps_target})
elseif("${default_build}" STREQUAL "safepdf")
add_custom_target(${LATEX_TARGET_NAME} DEPENDS ${safepdf_target})
elseif("${default_build}" STREQUAL "html")
add_custom_target(${LATEX_TARGET_NAME} DEPENDS ${html_target})
else()
message(SEND_ERROR "LATEX_DEFAULT_BUILD set to an invalid value. See the documentation for that variable.")
endif()
if(NOT LATEX_EXCLUDE_FROM_ALL)
add_custom_target(_${LATEX_TARGET_NAME} ALL DEPENDS ${LATEX_TARGET_NAME})
endif()
set_directory_properties(.
ADDITIONAL_MAKE_CLEAN_FILES "${auxiliary_clean_files}"
)
add_custom_target(${auxclean_target}
COMMENT "Cleaning auxiliary LaTeX files."
COMMAND ${CMAKE_COMMAND} -E remove ${auxiliary_clean_files}
)
add_dependencies(auxclean ${auxclean_target})
endfunction(add_latex_targets_internal)
function(add_latex_targets latex_main_input)
latex_get_output_path(output_dir)
parse_add_latex_arguments(ADD_LATEX_TARGETS ${latex_main_input} ${ARGN})
add_latex_targets_internal()
endfunction(add_latex_targets)
function(add_latex_document latex_main_input)
latex_get_output_path(output_dir)
if(output_dir)
parse_add_latex_arguments(add_latex_document ${latex_main_input} ${ARGN})
latex_copy_input_file(${LATEX_MAIN_INPUT})
foreach (bib_file ${LATEX_BIBFILES})
latex_copy_input_file(${bib_file})
endforeach (bib_file)
foreach (input ${LATEX_INPUTS})
latex_copy_input_file(${input})
endforeach(input)
latex_copy_globbed_files(${CMAKE_CURRENT_SOURCE_DIR}/*.cls ${output_dir})
latex_copy_globbed_files(${CMAKE_CURRENT_SOURCE_DIR}/*.bst ${output_dir})
latex_copy_globbed_files(${CMAKE_CURRENT_SOURCE_DIR}/*.clo ${output_dir})
latex_copy_globbed_files(${CMAKE_CURRENT_SOURCE_DIR}/*.sty ${output_dir})
latex_copy_globbed_files(${CMAKE_CURRENT_SOURCE_DIR}/*.ist ${output_dir})
latex_copy_globbed_files(${CMAKE_CURRENT_SOURCE_DIR}/*.fd ${output_dir})
add_latex_targets_internal()
endif()
endfunction(add_latex_document)
#############################################################################
# Actually do stuff
#############################################################################
if(LATEX_BUILD_COMMAND)
set(command_handled)
if("${LATEX_BUILD_COMMAND}" STREQUAL execute_latex)
latex_execute_latex()
set(command_handled TRUE)
endif()
if("${LATEX_BUILD_COMMAND}" STREQUAL makeglossaries)
latex_makeglossaries()
set(command_handled TRUE)
endif()
if("${LATEX_BUILD_COMMAND}" STREQUAL makenomenclature)
latex_makenomenclature()
set(command_handled TRUE)
endif()
if("${LATEX_BUILD_COMMAND}" STREQUAL correct_synctex)
latex_correct_synctex()
set(command_handled TRUE)
endif()
if("${LATEX_BUILD_COMMAND}" STREQUAL check_important_warnings)
latex_check_important_warnings()
set(command_handled TRUE)
endif()
if(NOT command_handled)
message(SEND_ERROR "Unknown command: ${LATEX_BUILD_COMMAND}")
endif()
else()
# Must be part of the actual configure (included from CMakeLists.txt).
latex_setup_variables()
latex_setup_targets()
endif()
# -*- coding: utf-8 -*-
#
# CAF documentation build configuration file, created by
# sphinx-quickstart on Fri Jun 3 11:27:36 2016.
#
# This file is execfile()d with the current directory set to its
# containing dir.
#
# Note that not all possible configuration values are present in this
# autogenerated file.
#
# All configuration values have a default; values that are commented out
# serve to show the default.
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
#
# import os
# import sys
# sys.path.insert(0, os.path.abspath('.'))
# -- General configuration ------------------------------------------------
# If your documentation needs a minimal Sphinx version, state it here.
#
# needs_sphinx = '1.0'
import sphinx_rtd_theme
# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones.
extensions = []
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
# The suffix(es) of source filenames.
# You can specify multiple suffix as a list of string:
#
# source_suffix = ['.rst', '.md']
source_suffix = '.rst'
# The encoding of source files.
#
# source_encoding = 'utf-8-sig'
# The master toctree document.
master_doc = 'index'
# General information about the project.
project = u'CAF'
copyright = u'2016, Dominik Charousset'
author = u'Dominik Charousset'
# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
# built documents.
#
# The short X.Y version.
version = u'@CAF_VERSION@'
# The full version, including alpha/beta/rc tags.
release = u'@CAF_RELEASE@'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
#
# This is also used if you do content translation via gettext catalogs.
# Usually you set "language" from the command line for these cases.
language = None
# There are two options for replacing |today|: either, you set today to some
# non-false value, then it is used:
#
# today = ''
#
# Else, today_fmt is used as the format for a strftime call.
#
# today_fmt = '%B %d, %Y'
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
# This patterns also effect to html_static_path and html_extra_path
exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
# The reST default role (used for this markup: `text`) to use for all
# documents.
#
# default_role = None
# If true, '()' will be appended to :func: etc. cross-reference text.
#
# add_function_parentheses = True
# If true, the current module name will be prepended to all description
# unit titles (such as .. function::).
#
# add_module_names = True
# If true, sectionauthor and moduleauthor directives will be shown in the
# output. They are ignored by default.
#
# show_authors = False
# The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'sphinx'
highlight_language = 'C++'
# A list of ignored prefixes for module index sorting.
# modindex_common_prefix = []
# If true, keep warnings as "system message" paragraphs in the built documents.
# keep_warnings = False
# If true, `todo` and `todoList` produce output, else they produce nothing.
todo_include_todos = False
# -- Options for HTML output ----------------------------------------------
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
#
html_theme = 'sphinx_rtd_theme'
# Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the
# documentation.
#
# html_theme_options = {}
# Add any paths that contain custom themes here, relative to this directory.
html_theme_path = [sphinx_rtd_theme.get_html_theme_path()]
# The name for this set of Sphinx documents.
# "<project> v<release> documentation" by default.
#
# html_title = u'CAF v0.15'
# A shorter title for the navigation bar. Default is the same as html_title.
#
# html_short_title = None
# The name of an image file (relative to this directory) to place at the top
# of the sidebar.
#
# html_logo = None
# The name of an image file (relative to this directory) to use as a favicon of
# the docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
# pixels large.
#
# html_favicon = None
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ['_static']
# Add any extra paths that contain custom files (such as robots.txt or
# .htaccess) here, relative to this directory. These files are copied
# directly to the root of the documentation.
#
# html_extra_path = []
# If not None, a 'Last updated on:' timestamp is inserted at every page
# bottom, using the given strftime format.
# The empty string is equivalent to '%b %d, %Y'.
#
# html_last_updated_fmt = None
# If true, SmartyPants will be used to convert quotes and dashes to
# typographically correct entities.
#
# html_use_smartypants = True
# Custom sidebar templates, maps document names to template names.
#
# html_sidebars = {}
# Additional templates that should be rendered to pages, maps page names to
# template names.
#
# html_additional_pages = {}
# If false, no module index is generated.
#
# html_domain_indices = True
# If false, no index is generated.
#
# html_use_index = True
# If true, the index is split into individual pages for each letter.
#
# html_split_index = False
# If true, links to the reST sources are added to the pages.
#
# html_show_sourcelink = True
# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
#
# html_show_sphinx = True
# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
#
# html_show_copyright = True
# If true, an OpenSearch description file will be output, and all pages will
# contain a <link> tag referring to it. The value of this option must be the
# base URL from which the finished HTML is served.
#
# html_use_opensearch = ''
# This is the file name suffix for HTML files (e.g. ".xhtml").
# html_file_suffix = None
# Language to be used for generating the HTML full-text search index.
# Sphinx supports the following languages:
# 'da', 'de', 'en', 'es', 'fi', 'fr', 'hu', 'it', 'ja'
# 'nl', 'no', 'pt', 'ro', 'ru', 'sv', 'tr', 'zh'
#
# html_search_language = 'en'
# A dictionary with options for the search language support, empty by default.
# 'ja' uses this config value.
# 'zh' user can custom change `jieba` dictionary path.
#
# html_search_options = {'type': 'default'}
# The name of a javascript file (relative to the configuration directory) that
# implements a search results scorer. If empty, the default will be used.
#
# html_search_scorer = 'scorer.js'
# Output file base name for HTML help builder.
htmlhelp_basename = 'CAFdoc'
# -- Options for LaTeX output ---------------------------------------------
latex_elements = {
# The paper size ('letterpaper' or 'a4paper').
#
# 'papersize': 'letterpaper',
# The font size ('10pt', '11pt' or '12pt').
#
# 'pointsize': '10pt',
# Additional stuff for the LaTeX preamble.
#
# 'preamble': '',
# Latex figure (float) alignment
#
# 'figure_align': 'htbp',
}
# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title,
# author, documentclass [howto, manual, or own class]).
latex_documents = [
(master_doc, 'CAF.tex', u'CAF Documentation',
u'Dominik Charousset', 'manual'),
]
# The name of an image file (relative to this directory) to place at the top of
# the title page.
#
# latex_logo = None
# For "manual" documents, if this is true, then toplevel headings are parts,
# not chapters.
#
# latex_use_parts = False
# If true, show page references after internal links.
#
# latex_show_pagerefs = False
# If true, show URL addresses after external links.
#
# latex_show_urls = False
# Documents to append as an appendix to all manuals.
#
# latex_appendices = []
# If false, no module index is generated.
#
# latex_domain_indices = True
# -- Options for manual page output ---------------------------------------
# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
man_pages = [
(master_doc, 'caf', u'CAF Documentation',
[author], 1)
]
# If true, show URL addresses after external links.
#
# man_show_urls = False
# -- Options for Texinfo output -------------------------------------------
# Grouping the document tree into Texinfo files. List of tuples
# (source start file, target name, title, author,
# dir menu entry, description, category)
texinfo_documents = [
(master_doc, 'CAF', u'CAF Documentation',
author, 'CAF', 'One line description of project.',
'Miscellaneous'),
]
# Documents to append as an appendix to all manuals.
#
# texinfo_appendices = []
# If false, no module index is generated.
#
# texinfo_domain_indices = True
# How to display URL addresses: 'footnote', 'no', or 'inline'.
#
# texinfo_show_urls = 'footnote'
# If true, do not generate a @detailmenu in the "Top" node's menu.
#
# texinfo_no_detailmenu = False
Version Information
===================
This version of the Manual was automatically generated from CAF commit
`@CAF_SHA@ <https://github.com/actor-framework/actor-framework/commit/@CAF_SHA@>`_.
CAF User Manual
===============
**C++ Actor Framework** version @CAF_RELEASE@.
Contents
========
\newcommand{\cafrelease}{@CAF_RELEASE@}
\newcommand{\cafsha}{@CAF_SHA@}
\section{Actors}
\label{actor}
Actors in CAF are a lightweight abstraction for units of computations. They
are active objects in the sense that they own their state and do not allow
others to access it. The only way to modify the state of an actor is sending
messages to it.
CAF provides several actor implementations, each covering a particular use
case. The available implementations differ in three characteristics: (1)
dynamically or statically typed, (2) class-based or function-based, and (3)
using asynchronous event handlers or blocking receives. These three
characteristics can be combined freely, with one exception: statically typed
actors are always event-based. For example, an actor can have dynamically typed
messaging, implement a class, and use blocking receives. The common base class
for all user-defined actors is called \lstinline^local_actor^.
Dynamically typed actors are more familiar to developers coming from Erlang or
Akka. They (usually) enable faster prototyping but require extensive unit
testing. Statically typed actors require more source code but enable the
compiler to verify communication between actors. Since CAF supports both,
developers can freely mix both kinds of actors to get the best of both worlds.
A good rule of thumb is to make use of static type checking for actors that are
visible across multiple translation units.
Actors that utilize the blocking receive API always require an exclusive thread
of execution. Event-based actors, on the other hand, are usually scheduled
cooperatively and are very lightweight with a memory footprint of only few
hundred bytes. Developers can exclude---detach---event-based actors that
potentially starve others from the cooperative scheduling while spawning it. A
detached actor lives in its own thread of execution.
\subsection{Environment / Actor Systems}
\label{actor-system}
All actors live in an \lstinline^actor_system^ representing an actor
environment including scheduler~\see{scheduler}, registry~\see{registry}, and
optional components such as a middleman~\see{middleman}. A single process can
have multiple \lstinline^actor_system^ instances, but this is usually not
recommended (a use case for multiple systems is to strictly separate two or
more sets of actors by running them in different schedulers). For configuration
and fine-tuning options of actor systems see \sref{system-config}. A
distributed CAF application consists of two or more connected actor systems. We
also refer to interconnected \lstinline^actor_system^ instances as a
\emph{distributed actor system}.
\clearpage
\subsection{Common Actor Base Types}
The following pseudo-UML depicts the class diagram for actors in CAF.
Irrelevant member functions and classes as well as mixins are omitted for
brevity. Selected individual classes are presented in more detail in the
following sections.
\singlefig{actor_types}%
{Actor Types in CAF}%
{actor-types}
\clearpage
\subsubsection{Class \lstinline^local_actor^}
The class \lstinline^local_actor^ is the root type for all user-defined actors
in CAF. It defines all common operations. However, users of the library
usually do not inherit from this class directly. Proper base classes for
user-defined actors are \lstinline^event_based_actor^ or
\lstinline^blocking_actor^. The following table also includes member function
inherited from \lstinline^monitorable_actor^ and \lstinline^abstract_actor^.
\begin{center}
\begin{tabular}{ll}
\textbf{Types} & ~ \\
\hline
\lstinline^mailbox_type^ & A concurrent, many-writers-single-reader queue type. \\
\hline
~ & ~ \\ \textbf{Constructors} & ~ \\
\hline
\lstinline^(actor_config&)^ & Constructs the actor using a config. \\
\hline
~ & ~ \\ \textbf{Observers} & ~ \\
\hline
\lstinline^actor_addr address()^ & Returns the address of this actor. \\
\hline
\lstinline^actor_system& system()^ & Returns \lstinline^context()->system()^. \\
\hline
\lstinline^actor_system& home_system()^ & Returns the system that spawned this actor. \\
\hline
\lstinline^execution_unit* context()^ & Returns underlying thread or current scheduler worker. \\
\hline
~ & ~ \\ \textbf{Customization Points} & ~ \\
\hline
\lstinline^on_exit()^ & Can be overridden to perform cleanup code. \\
\hline
\lstinline^const char* name()^ & Returns a debug name for this actor type. \\
\hline
~ & ~ \\ \textbf{Actor Management} & ~ \\
\hline
\lstinline^link_to(other)^ & Link to an actor \see{link}. \\
\hline
\lstinline^unlink_from(other)^ & Remove link to an actor \see{link}. \\
\hline
\lstinline^monitor(other)^ & Unidirectionally monitors an actor \see{monitor}. \\
\hline
\lstinline^demonitor(other)^ & Removes a monitor from \lstinline^whom^. \\
\hline
\lstinline^spawn(F fun, xs...)^ & Spawns a new actor from \lstinline^fun^. \\
\hline
\lstinline^spawn<T>(xs...)^ & Spawns a new actor of type \lstinline^T^. \\
\hline
~ & ~ \\ \textbf{Message Processing} & ~ \\
\hline
\lstinline^T make_response_promise<Ts...>()^ & Allows an actor to delay its response message. \\
\hline
\lstinline^T response(xs...)^ & Convenience function for creating fulfilled promises. \\
\hline
\end{tabular}
\end{center}
\clearpage
\subsubsection{Class \lstinline^scheduled_actor^}
All scheduled actors inherit from \lstinline^scheduled_actor^. This includes
statically and dynamically typed event-based actors as well as brokers
\see{broker}.
\begin{center}
\begin{tabular}{ll}
\textbf{Types} & ~ \\
\hline
\lstinline^pointer^ & \lstinline^scheduled_actor*^ \\
\hline
\lstinline^exception_handler^ & \lstinline^function<error (pointer, std::exception_ptr&)>^ \\
\hline
\lstinline^default_handler^ & \lstinline^function<result<message> (pointer, message_view&)>^ \\
\hline
\lstinline^error_handler^ & \lstinline^function<void (pointer, error&)>^ \\
\hline
\lstinline^down_handler^ & \lstinline^function<void (pointer, down_msg&)>^ \\
\hline
\lstinline^exit_handler^ & \lstinline^function<void (pointer, exit_msg&)>^ \\
\hline
~ & ~ \\ \textbf{Constructors} & ~ \\
\hline
\lstinline^(actor_config&)^ & Constructs the actor using a config. \\
\hline
~ & ~ \\ \textbf{Termination} & ~ \\
\hline
\lstinline^quit()^ & Stops this actor with normal exit reason. \\
\hline
\lstinline^quit(error x)^ & Stops this actor with error \lstinline^x^. \\
\hline
~ & ~ \\ \textbf{Special-purpose Handlers} & ~ \\
\hline
\lstinline^set_exception_handler(F f)^ & Installs \lstinline^f^ for converting exceptions to errors \see{error}. \\
\hline
\lstinline^set_down_handler(F f)^ & Installs \lstinline^f^ to handle down messages \see{down-message}. \\
\hline
\lstinline^set_exit_handler(F f)^ & Installs \lstinline^f^ to handle exit messages \see{exit-message}. \\
\hline
\lstinline^set_error_handler(F f)^ & Installs \lstinline^f^ to handle error messages (see \sref{error-message} and \sref{error}). \\
\hline
\lstinline^set_default_handler(F f)^ & Installs \lstinline^f^ as fallback message handler \see{default-handler}. \\
\hline
\end{tabular}
\end{center}
\clearpage
\subsubsection{Class \lstinline^blocking_actor^}
A blocking actor always lives in its own thread of execution. They are not as
lightweight as event-based actors and thus do not scale up to large numbers.
The primary use case for blocking actors is to use a \lstinline^scoped_actor^
for ad-hoc communication to selected actors. Unlike scheduled actors, CAF does
\textbf{not} dispatch system messages to special-purpose handlers. A blocking
actors receives \emph{all} messages regularly through its mailbox. A blocking
actor is considered \emph{done} only after it returned from \lstinline^act^ (or
from the implementation in function-based actors). A \lstinline^scoped_actor^
sends its exit messages as part of its destruction.
\begin{center}
\begin{tabular}{ll}
\textbf{Constructors} & ~ \\
\hline
\lstinline^(actor_config&)^ & Constructs the actor using a config. \\
\hline
~ & ~ \\ \textbf{Customization Points} & ~ \\
\hline
\lstinline^void act()^ & Implements the behavior of the actor. \\
\hline
~ & ~ \\ \textbf{Termination} & ~ \\
\hline
\lstinline^const error& fail_state()^ & Returns the current exit reason. \\
\hline
\lstinline^fail_state(error x)^ & Sets the current exit reason. \\
\hline
~ & ~ \\ \textbf{Actor Management} & ~ \\
\hline
\lstinline^wait_for(Ts... xs)^ & Blocks until all actors \lstinline^xs...^ are done. \\
\hline
\lstinline^await_all_other_actors_done()^ & Blocks until all other actors are done. \\
\hline
~ & ~ \\ \textbf{Message Handling} & ~ \\
\hline
\lstinline^receive(Ts... xs)^ & Receives a message using the callbacks \lstinline^xs...^. \\
\hline
\lstinline^receive_for(T& begin, T end)^ & See \sref{receive-loop}. \\
\hline
\lstinline^receive_while(F stmt)^ & See \sref{receive-loop}. \\
\hline
\lstinline^do_receive(Ts... xs)^ & See \sref{receive-loop}. \\
\hline
\end{tabular}
\end{center}
\clearpage
\subsection{Messaging Interfaces}
\label{interface}
Statically typed actors require abstract messaging interfaces to allow the
compiler to type-check actor communication. Interfaces in CAF are defined using
the variadic template \lstinline^typed_actor<...>^, which defines the proper
actor handle at the same time. Each template parameter defines one
\lstinline^input/output^ pair via
\lstinline^replies_to<X1,...,Xn>::with<Y1,...,Yn>^. For inputs that do not
generate outputs, \lstinline^reacts_to<X1,...,Xn>^ can be used as shortcut for
\lstinline^replies_to<X1,...,Xn>::with<void>^. In the same way functions cannot
be overloaded only by their return type, interfaces cannot accept one input
twice (possibly mapping it to different outputs). The example below defines a
messaging interface for a simple calculator.
\cppexample[17-21]{message_passing/calculator}
It is not required to create a type alias such as \lstinline^calculator_actor^,
but it makes dealing with statically typed actors much easier. Also, a central
alias definition eases refactoring later on.
Interfaces have set semantics. This means the following two type aliases
\lstinline^i1^ and \lstinline^i2^ are equal:
\begin{lstlisting}
using i1 = typed_actor<replies_to<A>::with<B>, replies_to<C>::with<D>>;
using i2 = typed_actor<replies_to<C>::with<D>, replies_to<A>::with<B>>;
\end{lstlisting}
Further, actor handles of type \lstinline^A^ are assignable to handles of type
\lstinline^B^ as long as \lstinline^B^ is a subset of \lstinline^A^.
For convenience, the class \lstinline^typed_actor<...>^ defines the member
types shown below to grant access to derived types.
\begin{center}
\begin{tabular}{ll}
\textbf{Types} & ~ \\
\hline
\lstinline^behavior_type^ & A statically typed set of message handlers. \\
\hline
\lstinline^base^ & Base type for actors, i.e., \lstinline^typed_event_based_actor<...>^. \\
\hline
\lstinline^pointer^ & A pointer of type \lstinline^base*^. \\
\hline
\lstinline^stateful_base<T>^ & See \sref{stateful-actor}. \\
\hline
\lstinline^stateful_pointer<T>^ & A pointer of type \lstinline^stateful_base<T>*^. \\
\hline
\lstinline^extend<Ts...>^ & Extend this typed actor with \lstinline^Ts...^. \\
\hline
\lstinline^extend_with<Other>^ & Extend this typed actor with all cases from \lstinline^Other^. \\
\hline
\end{tabular}
\end{center}
\clearpage
\subsection{Spawning Actors}
\label{spawn}
Both statically and dynamically typed actors are spawned from an
\lstinline^actor_system^ using the member function \lstinline^spawn^. The
function either takes a function as first argument or a class as first template
parameter. For example, the following functions and classes represent actors.
\cppexample[24-29]{message_passing/calculator}
Spawning an actor for each implementation is illustrated below.
\cppexample[140-145]{message_passing/calculator}
Additional arguments to \lstinline^spawn^ are passed to the constructor of a
class or used as additional function arguments, respectively. In the example
above, none of the three functions takes any argument other than the implicit
but optional \lstinline^self^ pointer.
\subsection{Function-based Actors}
\label{function-based}
When using a function or function object to implement an actor, the first
argument \emph{can} be used to capture a pointer to the actor itself. The type
of this pointer is usually \lstinline^event_based_actor*^ or
\lstinline^blocking_actor*^. The proper pointer type for any
\lstinline^typed_actor^ handle \lstinline^T^ can be obtained via
\lstinline^T::pointer^ \see{interface}.
Blocking actors simply implement their behavior in the function body. The actor
is done once it returns from that function.
Event-based actors can either return a \lstinline^behavior^
\see{message-handler} that is used to initialize the actor or explicitly set
the initial behavior by calling \lstinline^self->become(...)^. Due to the
asynchronous, event-based nature of this kind of actor, the function usually
returns immediately after setting a behavior (message handler) for the
\emph{next} incoming message. Hence, variables on the stack will be out of
scope once a message arrives. Managing state in function-based actors can be
done either via rebinding state with \lstinline^become^, using heap-located
data referenced via \lstinline^std::shared_ptr^ or by using the ``stateful
actor'' abstraction~\see{stateful-actor}.
The following three functions implement the prototypes shown in~\sref{spawn}
and illustrate one blocking actor and two event-based actors (statically and
dynamically typed).
\clearpage
\cppexample[31-72]{message_passing/calculator}
\clearpage
\subsection{Class-based Actors}
\label{class-based}
Implementing an actor using a class requires the following:
\begin{itemize}
\item Provide a constructor taking a reference of type
\lstinline^actor_config&^ as first argument, which is forwarded to the base
class. The config is passed implicitly to the constructor when calling
\lstinline^spawn^, which also forwards any number of additional arguments
to the constructor.
\item Override \lstinline^make_behavior^ for event-based actors and
\lstinline^act^ for blocking actors.
\end{itemize}
Implementing actors with classes works for all kinds of actors and allows
simple management of state via member variables. However, composing states via
inheritance can get quite tedious. For dynamically typed actors, composing
states is particularly hard, because the compiler cannot provide much help. For
statically typed actors, CAF also provides an API for composable
behaviors~\see{composable-behavior} that works well with inheritance. The
following three examples implement the forward declarations shown in
\sref{spawn}.
\cppexample[74-108]{message_passing/calculator}
\clearpage
\subsection{Stateful Actors}
\label{stateful-actor}
The stateful actor API makes it easy to maintain state in function-based
actors. It is also safer than putting state in member variables, because the
state ceases to exist after an actor is done and is not delayed until the
destructor runs. For example, if two actors hold a reference to each other via
member variables, they produce a cycle and neither will get destroyed. Using
stateful actors instead breaks the cycle, because references are destroyed when
an actor calls \lstinline^self->quit()^ (or is killed externally). The
following example illustrates how to implement stateful actors with static
typing as well as with dynamic typing.
\cppexample[18-44]{message_passing/cell}
Stateful actors are spawned in the same way as any other function-based actor
\see{function-based}.
\cppexample[49-50]{message_passing/cell}
\clearpage
\subsection{Actors from Composable Behaviors \experimental}
\label{composable-behavior}
When building larger systems, it is often useful to implement the behavior of
an actor in terms of other, existing behaviors. The composable behaviors in
CAF allow developers to generate a behavior class from a messaging
interface~\see{interface}.
The base type for composable behaviors is \lstinline^composable_behavior<T>^,
where \lstinline^T^ is a \lstinline^typed_actor<...>^. CAF maps each
\lstinline^replies_to<A,B,C>::with<D,E,F>^ in \lstinline^T^ to a pure virtual
member function with signature:
\begin{lstlisting}
result<D, E, F> operator()(param<A>, param<B>, param<C>);.
\end{lstlisting}
Note that \lstinline^operator()^ will take integral types as well as atom
constants simply by value. A \lstinline^result<T>^ accepts either a value of
type \lstinline^T^, a \lstinline^skip_t^ \see{default-handler}, an
\lstinline^error^ \see{error}, a \lstinline^delegated<T>^ \see{delegate}, or a
\lstinline^response_promise<T>^ \see{promise}. A \lstinline^result<void>^ is
constructed by returning \lstinline^unit^.
A behavior that combines the behaviors \lstinline^X^, \lstinline^Y^, and
\lstinline^Z^ must inherit from \lstinline^composed_behavior<X,Y,Z>^ instead of
inheriting from the three classes directly. The class
\lstinline^composed_behavior^ ensures that the behaviors are concatenated
correctly. In case one message handler is defined in multiple base types, the
\emph{first} type in declaration order ``wins''. For example, if \lstinline^X^
and \lstinline^Y^ both implement the interface
\lstinline^replies_to<int,int>::with<int>^, only the handler implemented in
\lstinline^X^ is active.
Any composable (or composed) behavior with no pure virtual member functions can
be spawned directly through an actor system by calling
\lstinline^system.spawn<...>()^, as shown below.
\cppexample[20-52]{composition/calculator_behavior}
\clearpage
The second example illustrates how to use non-primitive values that are wrapped
in a \lstinline^param<T>^ when working with composable behaviors. The purpose
of \lstinline^param<T>^ is to provide a single interface for both constant and
non-constant access. Constant access is modeled with the implicit conversion
operator to a const reference, the member function \lstinline^get()^, and
\lstinline^operator->^.
When acquiring mutable access to the represented value, CAF copies the value
before allowing mutable access to it if more than one reference to the value
exists. This copy-on-write optimization avoids race conditions by design, while
minimizing copy operations \see{copy-on-write}. A mutable reference is returned
from the member functions \lstinline^get_mutable()^ and \lstinline^move()^. The
latter is a convenience function for \lstinline^std::move(x.get_mutable())^.
The following example illustrates how to use \lstinline^param<std::string>^
when implementing a simple dictionary.
\cppexample[22-44]{composition/dictionary_behavior}
\subsection{Attaching Cleanup Code to Actors}
\label{attach}
Users can attach cleanup code to actors. This code is executed immediately if
the actor has already exited. Otherwise, the actor will execute it as part of
its termination. The following example attaches a function object to actors for
printing a custom string on exit.
\cppexample[46-50]{broker/simple_broker}
It is possible to attach code to remote actors. However, the cleanup code will
run on the local machine.
\subsection{Blocking Actors}
\label{blocking-actor}
Blocking actors always run in a separate thread and are not scheduled by CAF.
Unlike event-based actors, blocking actors have explicit, blocking
\emph{receive} functions. Further, blocking actors do not handle system
messages automatically via special-purpose callbacks \see{special-handler}.
This gives users full control over the behavior of blocking actors. However,
blocking actors still should follow conventions of the actor system. For
example, actors should unconditionally terminate after receiving an
\lstinline^exit_msg^ with reason \lstinline^exit_reason::kill^.
\subsubsection{Receiving Messages}
The function \lstinline^receive^ sequentially iterates over all elements in the
mailbox beginning with the first. It takes a message handler that is applied to
the elements in the mailbox until an element was matched by the handler. An
actor calling \lstinline^receive^ is blocked until it successfully dequeued a
message from its mailbox or an optional timeout occurs. Messages that are not
matched by the behavior are automatically skipped and remain in the mailbox.
\begin{lstlisting}
self->receive (
[](int x) { /* ... */ }
);
\end{lstlisting}
\subsubsection{Catch-all Receive Statements}
\label{catch-all}
Blocking actors can use inline catch-all callbacks instead of setting a default
handler \see{default-handler}. A catch-all case must be the last callback
before the optional timeout, as shown in the example below.
\begin{lstlisting}
self->receive(
[&](float x) {
// ...
},
[&](const down_msg& x) {
// ...
},
[&](const exit_msg& x) {
// ...
},
others >> [](message_view& x) -> result<message> {
// report unexpected message back to client
return sec::unexpected_message;
}
);
\end{lstlisting}
\clearpage
\subsubsection{Receive Loops}
\label{receive-loop}
Message handler passed to \lstinline^receive^ are temporary object at runtime.
Hence, calling \lstinline^receive^ inside a loop creates an unnecessary amount
of short-lived objects. CAF provides predefined receive loops to allow for
more efficient code.
\begin{lstlisting}
// BAD
std::vector<int> results;
for (size_t i = 0; i < 10; ++i)
receive (
[&](int value) {
results.push_back(value);
}
);
// GOOD
std::vector<int> results;
size_t i = 0;
receive_for(i, 10) (
[&](int value) {
results.push_back(value);
}
);
\end{lstlisting}
\begin{lstlisting}
// BAD
size_t received = 0;
while (received < 10) {
receive (
[&](int) {
++received;
}
);
} ;
// GOOD
size_t received = 0;
receive_while([&] { return received < 10; }) (
[&](int) {
++received;
}
);
\end{lstlisting}
\clearpage
\begin{lstlisting}
// BAD
size_t received = 0;
do {
receive (
[&](int) {
++received;
}
);
} while (received < 10);
// GOOD
size_t received = 0;
do_receive (
[&](int) {
++received;
}
).until([&] { return received >= 10; });
\end{lstlisting}
The examples above illustrate the correct usage of the three loops
\lstinline^receive_for^, \lstinline^receive_while^ and
\lstinline^do_receive(...).until^. It is possible to nest receives and receive
loops.
\begin{lstlisting}
bool running = true;
self->receive_while([&] { return running; }) (
[&](int value1) {
self->receive (
[&](float value2) {
aout(self) << value1 << " => " << value2 << endl;
}
);
},
// ...
);
\end{lstlisting}
\subsubsection{Scoped Actors}
\label{scoped-actors}
The class \lstinline^scoped_actor^ offers a simple way of communicating with
CAF actors from non-actor contexts. It overloads \lstinline^operator->^ to
return a \lstinline^blocking_actor*^. Hence, it behaves like the implicit
\lstinline^self^ pointer in functor-based actors, only that it ceases to exist
at scope end.
\begin{lstlisting}
void test(actor_system& system) {
scoped_actor self{system};
// spawn some actor
auto aut = self->spawn(my_actor_impl);
self->send(aut, "hi there");
// self will be destroyed automatically here; any
// actor monitoring it will receive down messages etc.
}
\end{lstlisting}
\section{Network I/O with Brokers}
\label{broker}
When communicating to other services in the network, sometimes low-level socket
I/O is inevitable. For this reason, CAF provides \emph{brokers}. A broker is
an event-based actor running in the middleman that multiplexes socket I/O. It
can maintain any number of acceptors and connections. Since the broker runs in
the middleman, implementations should be careful to consume as little time as
possible in message handlers. Brokers should outsource any considerable amount
of work by spawning new actors or maintaining worker actors.
\textit{Note that all UDP-related functionality is still \experimental.}
\subsection{Spawning Brokers}
Brokers are implemented as functions and are spawned by calling on of the three
following member functions of the middleman.
\begin{lstlisting}
template <spawn_options Os = no_spawn_options,
class F = std::function<void(broker*)>, class... Ts>
typename infer_handle_from_fun<F>::type
spawn_broker(F fun, Ts&&... xs);
template <spawn_options Os = no_spawn_options,
class F = std::function<void(broker*)>, class... Ts>
expected<typename infer_handle_from_fun<F>::type>
spawn_client(F fun, const std::string& host, uint16_t port, Ts&&... xs);
template <spawn_options Os = no_spawn_options,
class F = std::function<void(broker*)>, class... Ts>
expected<typename infer_handle_from_fun<F>::type>
spawn_server(F fun, uint16_t port, Ts&&... xs);
\end{lstlisting}
The function \lstinline^spawn_broker^ simply spawns a broker. The convenience
function \lstinline^spawn_client^ tries to connect to given host and port over
TCP and returns a broker managing this connection on success. Finally,
\lstinline^spawn_server^ opens a local TCP port and spawns a broker managing it
on success. There are no convenience functions spawn a UDP-based client or
server.
\subsection{Class \texttt{broker}}
\label{broker-class}
\begin{lstlisting}
void configure_read(connection_handle hdl, receive_policy::config config);
\end{lstlisting}
Modifies the receive policy for the connection identified by \lstinline^hdl^.
This will cause the middleman to enqueue the next \lstinline^new_data_msg^
according to the given \lstinline^config^ created by
\lstinline^receive_policy::exactly(x)^, \lstinline^receive_policy::at_most(x)^,
or \lstinline^receive_policy::at_least(x)^ (with \lstinline^x^ denoting the
number of bytes).
\begin{lstlisting}
void write(connection_handle hdl, size_t num_bytes, const void* buf)
void write(datagram_handle hdl, size_t num_bytes, const void* buf)
\end{lstlisting}
Writes data to the output buffer.
\begin{lstlisting}
void enqueue_datagram(datagram_handle hdl, std::vector<char> buf);
\end{lstlisting}
Enqueues a buffer to be sent as a datagram. Use of this function is encouraged
over write as it allows reuse of the buffer which can be returned to the broker
in a \lstinline^datagram_sent_msg^.
\begin{lstlisting}
void flush(connection_handle hdl);
void flush(datagram_handle hdl);
\end{lstlisting}
Sends the data from the output buffer.
\begin{lstlisting}
template <class F, class... Ts>
actor fork(F fun, connection_handle hdl, Ts&&... xs);
\end{lstlisting}
Spawns a new broker that takes ownership of a given connection.
\begin{lstlisting}
size_t num_connections();
\end{lstlisting}
Returns the number of open connections.
\begin{lstlisting}
void close(connection_handle hdl);
void close(accept_handle hdl);
void close(datagram_handle hdl);
\end{lstlisting}
Closes the endpoint related to the handle.
\begin{lstlisting}
expected<std::pair<accept_handle, uint16_t>>
add_tcp_doorman(uint16_t port = 0, const char* in = nullptr,
bool reuse_addr = false);
\end{lstlisting}
Creates new doorman that accepts incoming connections on a given port and
returns the handle to the doorman and the port in use or an error.
\begin{lstlisting}
expected<connection_handle>
add_tcp_scribe(const std::string& host, uint16_t port);
\end{lstlisting}
Creates a new scribe to connect to host:port and returns handle to it or an
error.
\begin{lstlisting}
expected<std::pair<datagram_handle, uint16_t>>
add_udp_datagram_servant(uint16_t port = 0, const char* in = nullptr,
bool reuse_addr = false);
\end{lstlisting}
Creates a datagram servant to handle incoming datagrams on a given port.
Returns the handle to the servant and the port in use or an error.
\begin{lstlisting}
expected<datagram_handle>
add_udp_datagram_servant(const std::string& host, uint16_t port);
\end{lstlisting}
Creates a datagram servant to send datagrams to host:port and returns a handle
to it or an error.
\subsection{Broker-related Message Types}
Brokers receive system messages directly from the middleman for connection and
acceptor events.
\textbf{Note:} brokers are \emph{required} to handle these messages immediately
regardless of their current state. Not handling the system messages from the
broker results in loss of data, because system messages are \emph{not}
delivered through the mailbox and thus cannot be skipped.
\begin{lstlisting}
struct new_connection_msg {
accept_handle source;
connection_handle handle;
};
\end{lstlisting}
Indicates that \lstinline^source^ accepted a new TCP connection identified by
\lstinline^handle^.
\begin{lstlisting}
struct new_data_msg {
connection_handle handle;
std::vector<char> buf;
};
\end{lstlisting}
Contains raw bytes received from \lstinline^handle^. The amount of data
received per event is controlled with \lstinline^configure_read^ (see
\ref{broker-class}). It is worth mentioning that the buffer is re-used whenever
possible.
\begin{lstlisting}
struct data_transferred_msg {
connection_handle handle;
uint64_t written;
uint64_t remaining;
};
\end{lstlisting}
This message informs the broker that the \lstinline^handle^ sent
\lstinline^written^ bytes with \lstinline^remaining^ bytes in the buffer. Note,
that these messages are not sent per default but must be explicitly enabled via
the member function \lstinline^ack_writes^.
\begin{lstlisting}
struct connection_closed_msg {
connection_handle handle;
};
struct acceptor_closed_msg {
accept_handle handle;
};
\end{lstlisting}
A \lstinline^connection_closed_msg^ or \lstinline^acceptor_closed_msg^ informs
the broker that one of its handles is no longer valid.
\begin{lstlisting}
struct connection_passivated_msg {
connection_handle handle;
};
struct acceptor_passivated_msg {
accept_handle handle;
};
\end{lstlisting}
A \lstinline^connection_passivated_msg^ or \lstinline^acceptor_passivated_msg^
informs the broker that one of its handles entered passive mode and no longer
accepts new data or connections \see{trigger}.
The following messages are related to UDP communication
(see~\sref{transport-protocols}. Since UDP is not connection oriented, there is
no equivalent to the \lstinline^new_connection_msg^ of TCP.
\begin{lstlisting}
struct new_datagram_msg {
datagram_handle handle;
network::receive_buffer buf;
};
\end{lstlisting}
Contains the raw bytes from \lstinline^handle^. The buffer always has a maximum
size of 65k to receive all regular UDP messages. The amount of bytes can be
queried via the \lstinline^.size()^ member function. Similar to TCP, the buffer
is reused when possible---please do not resize it.
\begin{lstlisting}
struct datagram_sent_msg {
datagram_handle handle;
uint64_t written;
std::vector<char> buf;
};
\end{lstlisting}
This message informs the broker that the \lstinline^handle^ sent a datagram of
\lstinline^written^ bytes. It includes the buffer that held the sent message to
allow its reuse. Note, that these messages are not sent per default but must be
explicitly enabled via the member function \lstinline^ack_writes^.
\begin{lstlisting}
struct datagram_servant_closed_msg {
std::vector<datagram_handle> handles;
};
\end{lstlisting}
A \lstinline^datagram_servant_closed_msg^ informs the broker that one of its
handles is no longer valid.
\begin{lstlisting}
struct datagram_servant_passivated_msg {
datagram_handle handle;
};
\end{lstlisting}
A \lstinline^datagram_servant_closed_msg^ informs the broker that one of its
handles entered passive mode and no longer accepts new data \see{trigger}.
\subsection{Manually Triggering Events \experimental}
\label{trigger}
Brokers receive new events as \lstinline^new_connection_msg^ and
\lstinline^new_data_msg^ as soon and as often as they occur, per default. This
means a fast peer can overwhelm a broker by sending it data faster than the
broker can process it. In particular if the broker outsources work items to
other actors, because work items can accumulate in the mailboxes of the
workers.
Calling \lstinline^self->trigger(x,y)^, where \lstinline^x^ is a connection or
acceptor handle and \lstinline^y^ is a positive integer, allows brokers to halt
activities after \lstinline^y^ additional events. Once a connection or acceptor
stops accepting new data or connections, the broker receives a
\lstinline^connection_passivated_msg^ or \lstinline^acceptor_passivated_msg^.
Brokers can stop activities unconditionally with \lstinline^self->halt(x)^ and
resume activities unconditionally with \lstinline^self->trigger(x)^.
\section{Common Pitfalls}
\label{pitfalls}
This Section highlights common mistakes or C++ subtleties that can show up when
programming in CAF.
\subsection{Defining Message Handlers}
\begin{itemize}
\item C++ evaluates comma-separated expressions from left-to-right, using only
the last element as return type of the whole expression. This means that
message handlers and behaviors must \emph{not} be initialized like this:
\begin{lstlisting}
message_handler wrong = (
[](int i) { /*...*/ },
[](float f) { /*...*/ }
);
\end{lstlisting}
The correct way to initialize message handlers and behaviors is to either
use the constructor or the member function \lstinline^assign^:
\begin{lstlisting}
message_handler ok1{
[](int i) { /*...*/ },
[](float f) { /*...*/ }
};
message_handler ok2;
// some place later
ok2.assign(
[](int i) { /*...*/ },
[](float f) { /*...*/ }
);
\end{lstlisting}
\end{itemize}
\subsection{Event-Based API}
\begin{itemize}
\item The member function \lstinline^become^ does not block, i.e., always
returns immediately. Thus, lambda expressions should \textit{always} capture
by value. Otherwise, all references on the stack will cause undefined
behavior if the lambda expression is executed.
\end{itemize}
\subsection{Requests}
\begin{itemize}
\item A handle returned by \lstinline^request^ represents \emph{exactly one}
response message. It is not possible to receive more than one response
message.
\item The handle returned by \lstinline^request^ is bound to the calling actor.
It is not possible to transfer a handle to a response to another actor.
\end{itemize}
\clearpage
\subsection{Sharing}
\begin{itemize}
\item It is strongly recommended to \textbf{not} share states between actors.
In particular, no actor shall ever access member variables or member
functions of another actor. Accessing shared memory segments concurrently
can cause undefined behavior that is incredibly hard to find and debug.
However, sharing \textit{data} between actors is fine, as long as the data
is \textit{immutable} and its lifetime is guaranteed to outlive all actors.
The simplest way to meet the lifetime guarantee is by storing the data in
smart pointers such as \lstinline^std::shared_ptr^. Nevertheless, the
recommended way of sharing informations is message passing. Sending the
same message to multiple actors does not result in copying the data several
times.
\end{itemize}
\section{Configuring Actor Applications}
\label{system-config}
CAF configures applications at startup using an
\lstinline^actor_system_config^ or a user-defined subclass of that type. The
config objects allow users to add custom types, to load modules, and to
fine-tune the behavior of loaded modules with command line options or
configuration files~\see{system-config-options}.
The following code example is a minimal CAF application with a
middleman~\see{middleman} but without any custom configuration options.
\begin{lstlisting}
void caf_main(actor_system& system) {
// ...
}
CAF_MAIN(io::middleman)
\end{lstlisting}
The compiler expands this example code to the following.
\begin{lstlisting}
void caf_main(actor_system& system) {
// ...
}
int main(int argc, char** argv) {
return exec_main<io::middleman>(caf_main, argc, argv);
}
\end{lstlisting}
The function \lstinline^exec_main^ creates a config object, loads all modules
requested in \lstinline^CAF_MAIN^ and then calls \lstinline^caf_main^. A
minimal implementation for \lstinline^main^ performing all these steps manually
is shown in the next example for the sake of completeness.
\begin{lstlisting}
int main(int argc, char** argv) {
actor_system_config cfg;
// read CLI options
cfg.parse(argc, argv);
// return immediately if a help text was printed
if (cfg.cli_helptext_printed)
return 0;
// load modules
cfg.load<io::middleman>();
// create actor system and call caf_main
actor_system system{cfg};
caf_main(system);
}
\end{lstlisting}
However, setting up config objects by hand is usually not necessary. CAF
automatically selects user-defined subclasses of
\lstinline^actor_system_config^ if \lstinline^caf_main^ takes a second
parameter by reference, as shown in the minimal example below.
\begin{lstlisting}
class my_config : public actor_system_config {
public:
my_config() {
// ...
}
};
void caf_main(actor_system& system, const my_config& cfg) {
// ...
}
CAF_MAIN()
\end{lstlisting}
Users can perform additional initialization, add custom program options, etc.
simply by implementing a default constructor.
\subsection{Loading Modules}
\label{system-config-module}
The simplest way to load modules is to use the macro \lstinline^CAF_MAIN^ and
to pass a list of all requested modules, as shown below.
\begin{lstlisting}
void caf_main(actor_system& system) {
// ...
}
CAF_MAIN(mod1, mod2, ...)
\end{lstlisting}
Alternatively, users can load modules in user-defined config classes.
\begin{lstlisting}
class my_config : public actor_system_config {
public:
my_config() {
load<mod1>();
load<mod2>();
// ...
}
};
\end{lstlisting}
The third option is to simply call \lstinline^x.load<mod1>()^ on a config
object \emph{before} initializing an actor system with it.
\subsection{Command Line Options and INI Configuration Files}
\label{system-config-options}
CAF organizes program options in categories and parses CLI arguments as well
as INI files. CLI arguments override values in the INI file which override
hard-coded defaults. Users can add any number of custom program options by
implementing a subtype of \lstinline^actor_system_config^. The example below
adds three options to the ``global'' category.
\cppexample[222-234]{remoting/distributed_calculator}
We create a new ``global'' category in \lstinline^custom_options_}^. Each
following call to \lstinline^add^ then appends individual options to the
category. The first argument to \lstinline^add^ is the associated variable. The
second argument is the name for the parameter, optionally suffixed with a
comma-separated single-character short name. The short name is only considered
for CLI parsing and allows users to abbreviate commonly used option names. The
third and final argument to \lstinline^add^ is a help text.
The custom \lstinline^config^ class allows end users to set the port for the
application to 42 with either \lstinline^--port=42^ (long name) or
\lstinline^-p 42^ (short name). The long option name is prefixed by the
category when using a different category than ``global''. For example, adding
the port option to the category ``foo'' means end users have to type
\lstinline^--foo.port=42^ when using the long name. Short names are unaffected
by the category, but have to be unique.
Boolean options do not require arguments. The member variable
\lstinline^server_mode^ is set to \lstinline^true^ if the command line contains
either \lstinline^--server-mode^ or \lstinline^-s^.
The example uses member variables for capturing user-provided settings for
simplicity. However, this is not required. For example,
\lstinline^add<bool>(...)^ allows omitting the first argument entirely. All
values of the configuration are accessible with \lstinline^get_or^. Note that
all global options can omit the \lstinline^"global."^ prefix.
CAF adds the program options ``help'' (with short names \lstinline^-h^ and
\lstinline^-?^) as well as ``long-help'' to the ``global'' category.
The default name for the INI file is \lstinline^caf-application.ini^. Users can
change the file name and path by passing \lstinline^--config-file=<path>^ on
the command line.
INI files are organized in categories. No value is allowed outside of a
category (no implicit ``global'' category). The parses uses the following
syntax:
\begin{tabular}{p{0.3\textwidth}p{0.65\textwidth}}
\lstinline^key=true^ & is a boolean \\
\lstinline^key=1^ & is an integer \\
\lstinline^key=1.0^ & is an floating point number \\
\lstinline^key=1ms^ & is an timespan \\
\lstinline^key='foo'^ & is an atom \\
\lstinline^key="foo"^ & is a string \\
\lstinline^key=[0, 1, ...]^ & is as a list \\
\lstinline^key={a=1, b=2, ...}^ & is a dictionary (map) \\
\end{tabular}
The following example INI file lists all standard options in CAF and their
default value. Note that some options such as \lstinline^scheduler.max-threads^
are usually detected at runtime and thus have no hard-coded default.
\clearpage
\iniexample{caf-application}
\clearpage
\subsection{Adding Custom Message Types}
\label{add-custom-message-type}
CAF requires serialization support for all of its message types
\see{type-inspection}. However, CAF also needs a mapping of unique type names
to user-defined types at runtime. This is required to deserialize arbitrary
messages from the network.
As an introductory example, we (again) use the following POD type
\lstinline^foo^.
\cppexample[24-27]{custom_type/custom_types_1}
To make \lstinline^foo^ serializable, we make it inspectable
\see{type-inspection}:
\cppexample[30-34]{custom_type/custom_types_1}
Finally, we give \lstinline^foo^ a platform-neutral name and add it to the list
of serializable types by using a custom config class.
\cppexample[75-78,81-84]{custom_type/custom_types_1}
\subsection{Adding Custom Error Types}
Adding a custom error type to the system is a convenience feature to allow
improve the string representation. Error types can be added by implementing a
render function and passing it to \lstinline^add_error_category^, as shown
in~\sref{custom-error}.
\clearpage
\subsection{Adding Custom Actor Types \experimental}
\label{add-custom-actor-type}
Adding actor types to the configuration allows users to spawn actors by their
name. In particular, this enables spawning of actors on a different node
\see{remote-spawn}. For our example configuration, we consider the following
simple \lstinline^calculator^ actor.
\cppexample[33-39]{remoting/remote_spawn}
Adding the calculator actor type to our config is achieved by calling
\lstinline^add_actor_type<T>^. Note that adding an actor type in this way
implicitly calls \lstinline^add_message_type<T>^ for typed actors
\see{add-custom-message-type}. This makes our \lstinline^calculator^ actor type
serializable and also enables remote nodes to spawn calculators anywhere in the
distributed actor system (assuming all nodes use the same config).
\cppexample[99-101,106-106,110-101]{remoting/remote_spawn}
Our final example illustrates how to spawn a \lstinline^calculator^ locally by
using its type name. Because the dynamic type name lookup can fail and the
construction arguments passed as message can mismatch, this version of
\lstinline^spawn^ returns \lstinline^expected<T>^.
\begin{lstlisting}
auto x = system.spawn<calculator>("calculator", make_message());
if (! x) {
std::cerr << "*** unable to spawn calculator: "
<< system.render(x.error()) << std::endl;
return;
}
calculator c = std::move(*x);
\end{lstlisting}
Adding dynamically typed actors to the config is achieved in the same way. When
spawning a dynamically typed actor in this way, the template parameter is
simply \lstinline^actor^. For example, spawning an actor "foo" which requires
one string is created with:
\begin{lstlisting}
auto worker = system.spawn<actor>("foo", make_message("bar"));
\end{lstlisting}
Because constructor (or function) arguments for spawning the actor are stored
in a \lstinline^message^, only actors with appropriate input types are allowed.
For example, pointer types are illegal. Hence users need to replace C-strings
with \lstinline^std::string^.
\clearpage
\subsection{Log Output}
\label{log-output}
Logging is disabled in CAF per default. It can be enabled by setting the
\lstinline^--with-log-level=^ option of the \lstinline^configure^ script to one
of ``error'', ``warning'', ``info'', ``debug'', or ``trace'' (from least output
to most). Alternatively, setting the CMake variable \lstinline^CAF_LOG_LEVEL^
to 0, 1, 2, 3, or 4 (from least output to most) has the same effect.
All logger-related configuration options listed here and in
\sref{system-config-options} are silently ignored if logging is disabled.
\subsubsection{File Name}
\label{log-output-file-name}
The output file is generated from the template configured by
\lstinline^logger-file-name^. This template supports the following variables.
\begin{tabular}{|p{0.2\textwidth}|p{0.75\textwidth}|}
\hline
\textbf{Variable} & \textbf{Output} \\
\hline
\texttt{[PID]} & The OS-specific process ID. \\
\hline
\texttt{[TIMESTAMP]} & The UNIX timestamp on startup. \\
\hline
\texttt{[NODE]} & The node ID of the CAF system. \\
\hline
\end{tabular}
\subsubsection{Console}
\label{log-output-console}
Console output is disabled per default. Setting \lstinline^logger-console^ to
either \lstinline^"uncolored"^ or \lstinline^"colored"^ prints log events to
\lstinline^std::clog^. Using the \lstinline^"colored"^ option will print the
log events in different colors depending on the severity level.
\subsubsection{Format Strings}
\label{log-output-format-strings}
CAF uses log4j-like format strings for configuring printing of individual
events via \lstinline^logger-file-format^ and
\lstinline^logger-console-format^. Note that format modifiers are not supported
at the moment. The recognized field identifiers are:
\begin{tabular}{|p{0.1\textwidth}|p{0.85\textwidth}|}
\hline
\textbf{Character} & \textbf{Output} \\
\hline
\texttt{c} & The category/component. This name is defined by the macro \lstinline^CAF_LOG_COMPONENT^. Set this macro before including any CAF header. \\
\hline
\texttt{C} & The full qualifier of the current function. For example, the qualifier of \lstinline^void ns::foo::bar()^ is printed as \lstinline^ns.foo^. \\
\hline
\texttt{d} & The date in ISO 8601 format, i.e., \lstinline^"YYYY-MM-DD hh:mm:ss"^. \\
\hline
\texttt{F} & The file name. \\
\hline
\texttt{L} & The line number. \\
\hline
\texttt{m} & The user-defined log message. \\
\hline
\texttt{M} & The name of the current function. For example, the name of \lstinline^void ns::foo::bar()^ is printed as \lstinline^bar^. \\
\hline
\texttt{n} & A newline. \\
\hline
\texttt{p} & The priority (severity level). \\
\hline
\texttt{r} & Elapsed time since starting the application in milliseconds. \\
\hline
\texttt{t} & ID of the current thread. \\
\hline
\texttt{a} & ID of the current actor (or ``actor0'' when not logging inside an actor). \\
\hline
\texttt{\%} & A single percent sign. \\
\hline
\end{tabular}
\subsubsection{Filtering}
\label{log-output-filtering}
The two configuration options \lstinline^logger-component-filter^ and
\lstinline^logger-verbosity^ reduce the amount of generated log events. The
former is a list of excluded component names and the latter can increase the
reported severity level (but not decrease it beyond the level defined at
compile time).
\section{Errors}
\label{error}
Errors in CAF have a code and a category, similar to
\lstinline^std::error_code^ and \lstinline^std::error_condition^. Unlike its
counterparts from the C++ standard library, \lstinline^error^ is
plattform-neutral and serializable. Instead of using category singletons, CAF
stores categories as atoms~\see{atom}. Errors can also include a message to
provide additional context information.
\subsection{Class Interface}
\begin{center}
\begin{tabular}{ll}
\textbf{Constructors} & ~ \\
\hline
\lstinline^(Enum x)^ & Construct error by calling \lstinline^make_error(x)^ \\
\hline
\lstinline^(uint8_t x, atom_value y)^ & Construct error with code \lstinline^x^ and category \lstinline^y^ \\
\hline
\lstinline^(uint8_t x, atom_value y, message z)^ & Construct error with code \lstinline^x^, category \lstinline^y^, and context \lstinline^z^ \\
\hline
~ & ~ \\ \textbf{Observers} & ~ \\
\hline
\lstinline^uint8_t code()^ & Returns the error code \\
\hline
\lstinline^atom_value category()^ & Returns the error category \\
\hline
\lstinline^message context()^ & Returns additional context information \\
\hline
\lstinline^explicit operator bool()^ & Returns \lstinline^code() != 0^ \\
\hline
\end{tabular}
\end{center}
\subsection{Add Custom Error Categories}
\label{custom-error}
Adding custom error categories requires three steps: (1)~declare an enum class
of type \lstinline^uint8_t^ with the first value starting at 1, (2)~implement a
free function \lstinline^make_error^ that converts the enum to an
\lstinline^error^ object, (3)~add the custom category to the actor system with
a render function. The last step is optional to allow users to retrieve a
better string representation from \lstinline^system.render(x)^ than
\lstinline^to_string(x)^ can offer. Note that any error code with value 0 is
interpreted as \emph{not-an-error}. The following example adds a custom error
category by performing the first two steps.
\cppexample[19-34]{message_passing/divider}
The implementation of \lstinline^to_string(error)^ is unable to call string
conversions for custom error categories. Hence,
\lstinline^to_string(make_error(math_error::division_by_zero))^ returns
\lstinline^"error(1, math)"^.
The following code adds a rendering function to the actor system to provide a
more satisfactory string conversion.
\cppexample[50-58]{message_passing/divider}
With the custom rendering function,
\lstinline^system.render(make_error(math_error::division_by_zero))^ returns
\lstinline^"math_error(division_by_zero)"^.
\clearpage
\subsection{System Error Codes}
\label{sec}
System Error Codes (SECs) use the error category \lstinline^"system"^. They
represent errors in the actor system or one of its modules and are defined as
follows.
\sourcefile[32-117]{libcaf_core/caf/sec.hpp}
%\clearpage
\subsection{Default Exit Reasons}
\label{exit-reason}
CAF uses the error category \lstinline^"exit"^ for default exit reasons. These
errors are usually fail states set by the actor system itself. The two
exceptions are \lstinline^exit_reason::user_shutdown^ and
\lstinline^exit_reason::kill^. The former is used in CAF to signalize orderly,
user-requested shutdown and can be used by programmers in the same way. The
latter terminates an actor unconditionally when used in \lstinline^send_exit^,
even if the default handler for exit messages~\see{exit-message} is overridden.
\sourcefile[29-49]{libcaf_core/caf/exit_reason.hpp}
\section{Frequently Asked Questions}
\label{faq}
This Section is a compilation of the most common questions via GitHub, chat,
and mailing list.
\subsection{Can I Encrypt CAF Communication?}
Yes, by using the OpenSSL module~\see{free-remoting-functions}.
\subsection{Can I Create Messages Dynamically?}
Yes.
Usually, messages are created implicitly when sending messages but can also be
created explicitly using \lstinline^make_message^. In both cases, types and
number of elements are known at compile time. To allow for fully dynamic
message generation, CAF also offers \lstinline^message_builder^:
\begin{lstlisting}
message_builder mb;
// prefix message with some atom
mb.append(strings_atom::value);
// fill message with some strings
std::vector<std::string> strings{/*...*/};
for (auto& str : strings)
mb.append(str);
// create the message
message msg = mb.to_message();
\end{lstlisting}
\subsection{What Debugging Tools Exist?}
The \lstinline^scripts/^ and \lstinline^tools/^ directories contain some useful
tools to aid in development and debugging.
\lstinline^scripts/atom.py^ converts integer atom values back into strings.
\lstinline^scripts/demystify.py^ replaces cryptic \lstinline^typed_mpi<...>^
templates with \lstinline^replies_to<...>::with<...>^ and
\lstinline^atom_constant<...>^ with a human-readable representation of the
actual atom.
\lstinline^scripts/caf-prof^ is an R script that generates plots from CAF
profiler output.
\lstinline^caf-vec^ is a (highly) experimental tool that annotates CAF logs
with vector timestamps. It gives you happens-before relations and a nice
visualization via \href{https://bestchai.bitbucket.io/shiviz/}{ShiViz}.
\section{Overview}
Compiling CAF requires CMake and a C++11-compatible compiler. To get and
compile the sources on UNIX-like systems, type the following in a terminal:
\begin{verbatim}
git clone https://github.com/actor-framework/actor-framework
cd actor-framework
./configure
make
make install [as root, optional]
\end{verbatim}
We recommended to run the unit tests as well:
\begin{verbatim}
make test
\end{verbatim}
If the output indicates an error, please submit a bug report that includes (a)
your compiler version, (b) your OS, and (c) the content of the file
\texttt{build/Testing/Temporary/LastTest.log}.
\subsection{Features}
\begin{itemize}
\item Lightweight, fast and efficient actor implementations
\item Network transparent messaging
\item Error handling based on Erlang's failure model
\item Pattern matching for messages as internal DSL to ease development
\item Thread-mapped actors for soft migration of existing applications
\item Publish/subscribe group communication
\end{itemize}
\subsection{Minimal Compiler Versions}
\begin{itemize}
\item GCC 4.8
\item Clang 3.4
\item Visual Studio 2015, Update 3
\end{itemize}
\subsection{Supported Operating Systems}
\begin{itemize}
\item Linux
\item Mac OS X
\item Windows (static library only)
\end{itemize}
\clearpage
\subsection{Hello World Example}
\cppexample{hello_world}
\section{Group Communication}
\label{groups}
CAF supports publish/subscribe-based group communication. Dynamically typed
actors can join and leave groups and send messages to groups. The following
example showcases the basic API for retrieving a group from a module by its
name, joining, and leaving.
\begin{lstlisting}
std::string module = "local";
std::string id = "foo";
auto expected_grp = system.groups().get(module, id);
if (! expected_grp) {
std::cerr << "*** cannot load group: "
<< system.render(expected_grp.error()) << std::endl;
return;
}
auto grp = std::move(*expected_grp);
scoped_actor self{system};
self->join(grp);
self->send(grp, "test");
self->receive(
[](const std::string& str) {
assert(str == "test");
}
);
self->leave(grp);
\end{lstlisting}
It is worth mentioning that the module \lstinline`"local"` is guaranteed to
never return an error. The example above uses the general API for retrieving
the group. However, local modules can be easier accessed by calling
\lstinline`system.groups().get_local(id)`, which returns \lstinline`group`
instead of \lstinline`expected<group>`.
\subsection{Anonymous Groups}
\label{anonymous-group}
Groups created on-the-fly with \lstinline^system.groups().anonymous()^ can be
used to coordinate a set of workers. Each call to this function returns a new,
unique group instance.
\subsection{Local Groups}
\label{local-group}
The \lstinline^"local"^ group module creates groups for in-process
communication. For example, a group for GUI related events could be identified
by \lstinline^system.groups().get_local("GUI events")^. The group ID
\lstinline^"GUI events"^ uniquely identifies a singleton group instance of the
module \lstinline^"local"^.
\subsection{Remote Groups}
\label{remote-group}
Calling\lstinline^system.middleman().publish_local_groups(port, addr)^ makes
all local groups available to other nodes in the network. The first argument
denotes the port, while the second (optional) parameter can be used to
whitelist IP addresses.
After publishing the group at one node (the server), other nodes (the clients)
can get a handle for that group by using the ``remote'' module:
\lstinline^system.groups().get("remote", "<group>@<host>:<port>")^. This
implementation uses N-times unicast underneath and the group is only available
as long as the hosting server is alive.
\section{Introduction}
Before diving into the API of CAF, we discuss the concepts behind it and
explain the terminology used in this manual.
\subsection{Actor Model}
The actor model describes concurrent entities---actors---that do not share
state and communicate only via asynchronous message passing. Decoupling
concurrently running software components via message passing avoids race
conditions by design. Actors can create---spawn---new actors and monitor each
other to build fault-tolerant, hierarchical systems. Since message passing is
network transparent, the actor model applies to both concurrency and
distribution.
Implementing applications on top of low-level primitives such as mutexes and
semaphores has proven challenging and error-prone. In particular when trying to
implement applications that scale up to many CPU cores. Queueing, starvation,
priority inversion, and false sharing are only a few of the issues that can
decrease performance significantly in mutex-based concurrency models. In the
extreme, an application written with the standard toolkit can run slower when
adding more cores.
The actor model has gained momentum over the last decade due to its high level
of abstraction and its ability to scale dynamically from one core to many cores
and from one node to many nodes. However, the actor model has not yet been
widely adopted in the native programming domain. With CAF, we contribute a
library for actor programming in C++ as open-source software to ease native
development of concurrent as well as distributed systems. In this regard, CAF
follows the C++ philosophy ``building the highest abstraction possible without
sacrificing performance''.
\subsection{Terminology}
CAF is inspired by other implementations based on the actor model such as
Erlang or Akka. It aims to provide a modern C++ API allowing for type-safe as
well as dynamically typed messaging. While there are similarities to other
implementations, we made many different design decisions that lead to slight
differences when comparing CAF to other actor frameworks.
\subsubsection{Dynamically Typed Actor}
A dynamically typed actor accepts any kind of message and dispatches on its
content dynamically at the receiver. This is the ``traditional'' messaging
style found in implementations like Erlang or Akka. The upside of this approach
is (usually) faster prototyping and less code. This comes at the cost of
requiring excessive testing.
\subsubsection{Statically Typed Actor}
CAF achieves static type-checking for actors by defining abstract messaging
interfaces. Since interfaces define both input and output types, CAF is able to
verify messaging protocols statically. The upside of this approach is much
higher robustness to code changes and fewer possible runtime errors. This comes
at an increase in required source code, as developers have to define and use
messaging interfaces.
\subsubsection{Actor References}
\label{actor-reference}
CAF uses reference counting for actors. The three ways to store a reference to
an actor are addresses, handles, and pointers. Note that \emph{address} does
not refer to a \emph{memory region} in this context.
\paragraph{Address}
\label{actor-address}
Each actor has a (network-wide) unique logical address. This identifier is
represented by \lstinline^actor_addr^, which allows to identify and monitor an
actor. Unlike other actor frameworks, CAF does \emph{not} allow users to send
messages to addresses. This limitation is due to the fact that the address does
not contain any type information. Hence, it would not be safe to send it a
message, because the receiving actor might use a statically typed interface
that does not accept the given message. Because an \lstinline^actor_addr^ fills
the role of an identifier, it has \emph{weak reference semantics}
\see{reference-counting}.
\paragraph{Handle}
\label{actor-handle}
An actor handle contains the address of an actor along with its type
information and is required for sending messages to actors. The distinction
between handles and addresses---which is unique to CAF when comparing it to
other actor systems---is a consequence of the design decision to enforce static
type checking for all messages. Dynamically typed actors use \lstinline^actor^
handles, while statically typed actors use \lstinline^typed_actor<...>^
handles. Both types have \emph{strong reference semantics}
\see{reference-counting}.
\paragraph{Pointer}
\label{actor-pointer}
In a few instances, CAF uses \lstinline^strong_actor_ptr^ to refer to an actor
using \emph{strong reference semantics} \see{reference-counting} without
knowing the proper handle type. Pointers must be converted to a handle via
\lstinline^actor_cast^ \see{actor-cast} prior to sending messages. A
\lstinline^strong_actor_ptr^ can be \emph{null}.
\subsubsection{Spawning}
``Spawning'' an actor means to create and run a new actor.
\subsubsection{Monitor}
\label{monitor}
A monitored actor sends a down message~\see{down-message} to all actors
monitoring it as part of its termination. This allows actors to supervise other
actors and to take actions when one of the supervised actors fails, i.e.,
terminates with a non-normal exit reason.
\subsubsection{Link}
\label{link}
A link is a bidirectional connection between two actors. Each actor sends an
exit message~\see{exit-message} to all of its links as part of its termination.
Unlike down messages, exit messages cause the receiving actor to terminate as
well when receiving a non-normal exit reason per default. This allows
developers to create a set of actors with the guarantee that either all or no
actors are alive. Actors can override the default handler to implement error
recovery strategies.
\subsection{Experimental Features}
Sections that discuss experimental features are highlighted with \experimental.
The API of such features is not stable. This means even minor updates to CAF
can come with breaking changes to the API or even remove a feature completely.
However, we encourage developers to extensively test such features and to start
discussions to uncover flaws, report bugs, or tweaking the API in order to
improve a feature or streamline it to cover certain use cases.
\section{Managing Groups of Workers \experimental}
\label{worker-groups}
When managing a set of workers, a central actor often dispatches requests to a
set of workers. For this purpose, the class \lstinline^actor_pool^ implements a
lightweight abstraction for managing a set of workers using a dispatching
policy. Unlike groups, pools usually own their workers.
Pools are created using the static member function \lstinline^make^, which
takes either one argument (the policy) or three (number of workers, factory
function for workers, and dispatching policy). After construction, one can add
new workers via messages of the form \texttt{('SYS', 'PUT', worker)}, remove
workers with \texttt{('SYS', 'DELETE', worker)}, and retrieve the set of
workers as \lstinline^vector<actor>^ via \texttt{('SYS', 'GET')}.
An actor pool takes ownership of its workers. When forced to quit, it sends an
exit messages to all of its workers, forcing them to quit as well. The pool
also monitors all of its workers.
Pools do not cache messages, but enqueue them directly in a workers mailbox.
Consequently, a terminating worker loses all unprocessed messages. For more
advanced caching strategies, such as reliable message delivery, users can
implement their own dispatching policies.
\subsection{Dispatching Policies}
A dispatching policy is a functor with the following signature:
\begin{lstlisting}
using uplock = upgrade_lock<detail::shared_spinlock>;
using policy = std::function<void (actor_system& sys,
uplock& guard,
const actor_vec& workers,
mailbox_element_ptr& ptr,
execution_unit* host)>;
\end{lstlisting}
The argument \lstinline^guard^ is a shared lock that can be upgraded for unique
access if the policy includes a critical section. The second argument is a
vector containing all workers managed by the pool. The argument \lstinline^ptr^
contains the full message as received by the pool. Finally, \lstinline^host^ is
the current scheduler context that can be used to enqueue workers into the
corresponding job queue.
The actor pool class comes with a set predefined policies, accessible via
factory functions, for convenience.
\begin{lstlisting}
actor_pool::policy actor_pool::round_robin();
\end{lstlisting}
This policy forwards incoming requests in a round-robin manner to workers.
There is no guarantee that messages are consumed, i.e., work items are lost if
the worker exits before processing all of its messages.
\begin{lstlisting}
actor_pool::policy actor_pool::broadcast();
\end{lstlisting}
This policy forwards \emph{each} message to \emph{all} workers. Synchronous
messages to the pool will be received by all workers, but the client will only
recognize the first arriving response message---or error---and discard
subsequent messages. Note that this is not caused by the policy itself, but a
consequence of forwarding synchronous messages to more than one actor.
\begin{lstlisting}
actor_pool::policy actor_pool::random();
\end{lstlisting}
This policy forwards incoming requests to one worker from the pool chosen
uniformly at random. Analogous to \lstinline^round_robin^, this policy does not
cache or redispatch messages.
\begin{lstlisting}
using join = function<void (T&, message&)>;
using split = function<void (vector<pair<actor, message>>&, message&)>;
template <class T>
static policy split_join(join jf, split sf = ..., T init = T());
\end{lstlisting}
This policy models split/join or scatter/gather work flows, where a work item
is split into as many tasks as workers are available and then the individuals
results are joined together before sending the full result back to the client.
The join function is responsible for ``glueing'' all result messages together
to create a single result. The function is called with the result object
(initialed using \lstinline^init^) and the current result messages from a
worker.
The first argument of a split function is a mapping from actors (workers) to
tasks (messages). The second argument is the input message. The default split
function is a broadcast dispatching, sending each worker the original request.
\section{Message Handlers}
\label{message-handler}
Actors can store a set of callbacks---usually implemented as lambda
expressions---using either \lstinline^behavior^ or \lstinline^message_handler^.
The former stores an optional timeout, while the latter is composable.
\subsection{Definition and Composition}
As the name implies, a \lstinline^behavior^ defines the response of an actor to
messages it receives. The optional timeout allows an actor to dynamically
change its behavior when not receiving message after a certain amount of time.
\begin{lstlisting}
message_handler x1{
[](int i) { /*...*/ },
[](double db) { /*...*/ },
[](int a, int b, int c) { /*...*/ }
};
\end{lstlisting}
In our first example, \lstinline^x1^ models a behavior accepting messages that
consist of either exactly one \lstinline^int^, or one \lstinline^double^, or
three \lstinline^int^ values. Any other message is not matched and gets
forwarded to the default handler \see{default-handler}.
\begin{lstlisting}
message_handler x2{
[](double db) { /*...*/ },
[](double db) { /* - unrachable - */ }
};
\end{lstlisting}
Our second example illustrates an important characteristic of the matching
mechanism. Each message is matched against the callbacks in the order they are
defined. The algorithm stops at the first match. Hence, the second callback in
\lstinline^x2^ is unreachable.
\begin{lstlisting}
message_handler x3 = x1.or_else(x2);
message_handler x4 = x2.or_else(x1);
\end{lstlisting}
Message handlers can be combined using \lstinline^or_else^. This composition is
not commutative, as our third examples illustrates. The resulting message
handler will first try to handle a message using the left-hand operand and will
fall back to the right-hand operand if the former did not match. Thus,
\lstinline^x3^ behaves exactly like \lstinline^x1^. This is because the second
callback in \lstinline^x1^ will consume any message with a single
\lstinline^double^ and both callbacks in \lstinline^x2^ are thus unreachable.
The handler \lstinline^x4^ will consume messages with a single
\lstinline^double^ using the first callback in \lstinline^x2^, essentially
overriding the second callback in \lstinline^x1^.
\clearpage
\subsection{Atoms}
\label{atom}
Defining message handlers in terms of callbacks is convenient, but requires a
simple way to annotate messages with meta data. Imagine an actor that provides
a mathematical service for integers. It receives two integers, performs a
user-defined operation and returns the result. Without additional context, the
actor cannot decide whether it should multiply or add the integers. Thus, the
operation must be encoded into the message. The Erlang programming language
introduced an approach to use non-numerical constants, so-called
\textit{atoms}, which have an unambiguous, special-purpose type and do not have
the runtime overhead of string constants.
Atoms in CAF are mapped to integer values at compile time. This mapping is
guaranteed to be collision-free and invertible, but limits atom literals to ten
characters and prohibits special characters. Legal characters are
\lstinline^_0-9A-Za-z^ and the whitespace character. Atoms are created using
the \lstinline^constexpr^ function \lstinline^atom^, as the following example
illustrates.
\begin{lstlisting}
atom_value a1 = atom("add");
atom_value a2 = atom("multiply");
\end{lstlisting}
\textbf{Warning}: The compiler cannot enforce the restrictions at compile time,
except for a length check. The assertion \lstinline^atom("!?") != atom("?!")^
is not true, because each invalid character translates to a whitespace
character.
While the \lstinline^atom_value^ is computed at compile time, it is not
uniquely typed and thus cannot be used in the signature of a callback. To
accomplish this, CAF offers compile-time \emph{atom constants}.
\begin{lstlisting}
using add_atom = atom_constant<atom("add")>;
using multiply_atom = atom_constant<atom("multiply")>;
\end{lstlisting}
Using these constants, we can now define message passing interfaces in a
convenient way:
\begin{lstlisting}
behavior do_math{
[](add_atom, int a, int b) {
return a + b;
},
[](multiply_atom, int a, int b) {
return a * b;
}
};
// caller side: send(math_actor, add_atom::value, 1, 2)
\end{lstlisting}
Atom constants define a static member \lstinline^value^. Please note that this
static \lstinline^value^ member does \emph{not} have the type
\lstinline^atom_value^, unlike \lstinline^std::integral_constant^ for example.
\section{Message Passing}
\label{message-passing}
Message passing in CAF is always asynchronous. Further, CAF neither guarantees
message delivery nor message ordering in a distributed setting. CAF uses TCP
per default, but also enables nodes to send messages to other nodes without
having a direct connection. In this case, messages are forwarded by
intermediate nodes and can get lost if one of the forwarding nodes fails.
Likewise, forwarding paths can change dynamically and thus cause messages to
arrive out of order.
The messaging layer of CAF has three primitives for sending messages:
\lstinline^send^, \lstinline^request^, and \lstinline^delegate^. The former
simply enqueues a message to the mailbox the receiver. The latter two are
discussed in more detail in \sref{request} and \sref{delegate}.
\subsection{Structure of Mailbox Elements}
\label{mailbox-element}
When enqueuing a message to the mailbox of an actor, CAF wraps the content of
the message into a \lstinline^mailbox_element^ (shown below) to add meta data
and processing paths.
\singlefig{mailbox_element}{UML class diagram for \lstinline^mailbox_element^}{mailbox_element}
The sender is stored as a \lstinline^strong_actor_ptr^ \see{actor-pointer} and
denotes the origin of the message. The message ID is either 0---invalid---or a
positive integer value that allows the sender to match a response to its
request. The \lstinline^stages^ vector stores the path of the message. Response
messages, i.e., the returned values of a message handler, are sent to
\lstinline^stages.back()^ after calling \lstinline^stages.pop_back()^. This
allows CAF to build pipelines of arbitrary size. If no more stage is left, the
response reaches the sender. Finally, \lstinline^content()^ grants access to
the type-erased tuple storing the message itself.
Mailbox elements are created by CAF automatically and are usually invisible to
the programmer. However, understanding how messages are processed internally
helps understanding the behavior of the message passing layer.
It is worth mentioning that CAF usually wraps the mailbox element and its
content into a single object in order to reduce the number of memory
allocations.
\subsection{Copy on Write}
\label{copy-on-write}
CAF allows multiple actors to implicitly share message contents, as long as no
actor performs writes. This allows groups~\see{groups} to send the same content
to all subscribed actors without any copying overhead.
Actors copy message contents whenever other actors hold references to it and if
one or more arguments of a message handler take a mutable reference.
\subsection{Requirements for Message Types}
Message types in CAF must meet the following requirements:
\begin{enumerate}
\item Serializable or inspectable \see{type-inspection}
\item Default constructible
\item Copy constructible
\end{enumerate}
A type is serializable if it provides free function \lstinline^serialize(Serializer&, T&)^ or \lstinline^serialize(Serializer&, T&, const unsigned int)^. Accordingly, a type is inspectable if it provides a free function \lstinline^inspect(Inspector&, T&)^.
Requirement 2 is a consequence of requirement 1, because CAF needs to be able
to create an object of a type before it can call \lstinline^serialize^ or
\lstinline^inspect^ on it. Requirement 3 allows CAF to implement Copy on
Write~\see{copy-on-write}.
\subsection{Default and System Message Handlers}
\label{special-handler}
CAF has three system-level message types (\lstinline^down_msg^,
\lstinline^exit_msg^, and \lstinline^error^) that all actor should handle
regardless of there current state. Consequently, event-based actors handle such
messages in special-purpose message handlers. Additionally, event-based actors
have a fallback handler for unmatched messages. Note that blocking actors have
neither of those special-purpose handlers \see{blocking-actor}.
\subsubsection{Down Handler}
\label{down-message}
Actors can monitor the lifetime of other actors by calling \lstinline^self->monitor(other)^. This will cause the runtime system of CAF to send a \lstinline^down_msg^ for \lstinline^other^ if it dies. Actors drop down messages unless they provide a custom handler via \lstinline^set_down_handler(f)^, where \lstinline^f^ is a function object with signature \lstinline^void (down_msg&)^ or \lstinline^void (scheduled_actor*, down_msg&)^. The latter signature allows users to implement down message handlers as free function.
\subsubsection{Exit Handler}
\label{exit-message}
Bidirectional monitoring with a strong lifetime coupling is established by calling \lstinline^self->link_to(other)^. This will cause the runtime to send an \lstinline^exit_msg^ if either \lstinline^this^ or \lstinline^other^ dies. Per default, actors terminate after receiving an \lstinline^exit_msg^ unless the exit reason is \lstinline^exit_reason::normal^. This mechanism propagates failure states in an actor system. Linked actors form a sub system in which an error causes all actors to fail collectively. Actors can override the default handler via \lstinline^set_exit_handler(f)^, where \lstinline^f^ is a function object with signature \lstinline^void (exit_message&)^ or \lstinline^void (scheduled_actor*, exit_message&)^.
\subsubsection{Error Handler}
\label{error-message}
Actors send error messages to others by returning an \lstinline^error^ \see{error} from a message handler. Similar to exit messages, error messages usually cause the receiving actor to terminate, unless a custom handler was installed via \lstinline^set_error_handler(f)^, where \lstinline^f^ is a function object with signature \lstinline^void (error&)^ or \lstinline^void (scheduled_actor*, error&)^. Additionally, \lstinline^request^ accepts an error handler as second argument to handle errors for a particular request~\see{error-response}. The default handler is used as fallback if \lstinline^request^ is used without error handler.
\subsubsection{Default Handler}
\label{default-handler}
The default handler is called whenever the behavior of an actor did not match
the input. Actors can change the default handler by calling
\lstinline^set_default_handler^. The expected signature of the function object
is \lstinline^result<message> (scheduled_actor*, message_view&)^, whereas the
\lstinline^self^ pointer can again be omitted. The default handler can return a
response message or cause the runtime to \emph{skip} the input message to allow
an actor to handle it in a later state. CAF provides the following built-in
implementations: \lstinline^reflect^, \lstinline^reflect_and_quit^,
\lstinline^print_and_drop^, \lstinline^drop^, and \lstinline^skip^. The former
two are meant for debugging and testing purposes and allow an actor to simply
return an input. The next two functions drop unexpected messages with or
without printing a warning beforehand. Finally, \lstinline^skip^ leaves the
input message in the mailbox. The default is \lstinline^print_and_drop^.
\subsection{Requests}
\label{request}
A main feature of CAF is its ability to couple input and output types via the
type system. For example, a \lstinline^typed_actor<replies_to<int>::with<int>>^
essentially behaves like a function. It receives a single \lstinline^int^ as
input and responds with another \lstinline^int^. CAF embraces this functional
take on actors by simply creating response messages from the result of message
handlers. This allows CAF to match \emph{request} to \emph{response} messages
and to provide a convenient API for this style of communication.
\subsubsection{Sending Requests and Handling Responses}
\label{handling-response}
Actors send request messages by calling \lstinline^request(receiver, timeout, content...)^. This function returns an intermediate object that allows an actor to set a one-shot handler for the response message. Event-based actors can use either \lstinline^request(...).then^ or \lstinline^request(...).await^. The former multiplexes the one-shot handler with the regular actor behavior and handles requests as they arrive. The latter suspends the regular actor behavior until all awaited responses arrive and handles requests in LIFO order. Blocking actors always use \lstinline^request(...).receive^, which blocks until the one-shot handler was called. Actors receive a \lstinline^sec::request_timeout^ \see{sec} error message~\see{error-message} if a timeout occurs. Users can set the timeout to \lstinline^infinite^ for unbound operations. This is only recommended if the receiver is running locally.
In our following example, we use the simple cell actors shown below as
communication endpoints.
\cppexample[20-37]{message_passing/request}
The first part of the example illustrates how event-based actors can use either
\lstinline^then^ or \lstinline^await^.
\cppexample[39-51]{message_passing/request}
\clearpage
The second half of the example shows a blocking actor making use of
\lstinline^receive^. Note that blocking actors have no special-purpose handler
for error messages and therefore are required to pass a callback for error
messages when handling response messages.
\cppexample[53-64]{message_passing/request}
We spawn five cells and assign the values 0, 1, 4, 9, and 16.
\cppexample[67-69]{message_passing/request}
When passing the \lstinline^cells^ vector to our three different
implementations, we observe three outputs. Our \lstinline^waiting_testee^ actor
will always print:
{\footnotesize\begin{verbatim}
cell #9 -> 16
cell #8 -> 9
cell #7 -> 4
cell #6 -> 1
cell #5 -> 0
\end{verbatim}}
This is because \lstinline^await^ puts the one-shots handlers onto a stack and
enforces LIFO order by re-ordering incoming response messages.
The \lstinline^multiplexed_testee^ implementation does not print its results in
a predicable order. Response messages arrive in arbitrary order and are handled
immediately.
Finally, the \lstinline^blocking_testee^ implementation will always print:
{\footnotesize\begin{verbatim}
cell #5 -> 0
cell #6 -> 1
cell #7 -> 4
cell #8 -> 9
cell #9 -> 16
\end{verbatim}}
Both event-based approaches send all requests, install a series of one-shot
handlers, and then return from the implementing function. In contrast, the
blocking function waits for a response before sending another request.
\clearpage
\subsubsection{Error Handling in Requests}
\label{error-response}
Requests allow CAF to unambiguously correlate request and response messages.
This is also true if the response is an error message. Hence, CAF allows to
add an error handler as optional second parameter to \lstinline^then^ and
\lstinline^await^ (this parameter is mandatory for \lstinline^receive^). If no
such handler is defined, the default error handler \see{error-message} is used
as a fallback in scheduled actors.
As an example, we consider a simple divider that returns an error on a division
by zero. This examples uses a custom error category~\see{error}.
\cppexample[19-25,35-48]{message_passing/divider}
When sending requests to the divider, we use a custom error handlers to report
errors to the user.
\cppexample[68-77]{message_passing/divider}
\clearpage
\subsection{Delaying Messages}
\label{delay-message}
Messages can be delayed by using the function \lstinline^delayed_send^, as
illustrated in the following time-based loop example.
\cppexample[56-75]{message_passing/dancing_kirby}
\clearpage
\subsection{Delegating Messages}
\label{delegate}
Actors can transfer responsibility for a request by using \lstinline^delegate^.
This enables the receiver of the delegated message to reply as usual---simply
by returning a value from its message handler---and the original sender of the
message will receive the response. The following diagram illustrates request
delegation from actor B to actor C.
\begin{footnotesize}
\begin{verbatim}
A B C
| | |
| ---(request)---> | |
| | ---(delegate)--> |
| X |---\
| | | compute
| | | result
| |<--/
| <-------------(reply)-------------- |
| X
|---\
| | handle
| | response
|<--/
|
X
\end{verbatim}
\end{footnotesize}
Returning the result of \lstinline^delegate(...)^ from a message handler, as
shown in the example below, suppresses the implicit response message and allows
the compiler to check the result type when using statically typed actors.
\cppexample[15-42]{message_passing/delegating}
\subsection{Response Promises}
\label{promise}
Response promises allow an actor to send and receive other messages prior to
replying to a particular request. Actors create a response promise using
\lstinline^self->make_response_promise<Ts...>()^, where \lstinline^Ts^ is a
template parameter pack describing the promised return type. Dynamically typed
actors simply call \lstinline^self->make_response_promise()^. After retrieving
a promise, an actor can fulfill it by calling the member function
\lstinline^deliver(...)^, as shown in the following example.
\cppexample[18-43]{message_passing/promises}
\clearpage
\subsection{Message Priorities}
By default, all messages have the default priority, i.e.,
\lstinline^message_priority::normal^. Actors can send urgent messages by
setting the priority explicitly:
\lstinline^send<message_priority::high>(dst,...)^. Urgent messages are put into
a different queue of the receiver's mailbox. Hence, long wait delays can be
avoided for urgent communication.
\section{Type-Erased Tuples, Messages and Message Views}
\label{message}
Messages in CAF are stored in type-erased tuples. The actual message type
itself is usually hidden, as actors use pattern matching to decompose messages
automatically. However, the classes \lstinline^message^ and
\lstinline^message_builder^ allow more advanced use cases than only sending
data from one actor to another.
The interface \lstinline^type_erased_tuple^ encapsulates access to arbitrary
data. This data can be stored on the heap or on the stack. A
\lstinline^message^ is a type-erased tuple that is always heap-allocated and
uses copy-on-write semantics. When dealing with "plain" type-erased tuples,
users are required to check if a tuple is referenced by others via
\lstinline^type_erased_tuple::shared^ before modifying its content.
The convenience class \lstinline^message_view^ holds a reference to either a
stack-located \lstinline^type_erased_tuple^ or a \lstinline^message^. The
content of the data can be access via \lstinline^message_view::content^ in both
cases, which returns a \lstinline^type_erased_tuple&^. The content of the view
can be forced into a message object by calling
\lstinline^message_view::move_content_to_message^. This member function either
returns the stored message object or moves the content of a stack-allocated
tuple into a new message.
\subsection{RTTI and Type Numbers}
All builtin types in CAF have a non-zero 6-bit \emph{type number}. All
user-defined types are mapped to 0. When querying the run-time type information
(RTTI) for individual message or tuple elements, CAF returns a pair consisting
of an integer and a pointer to \lstinline^std::type_info^. The first value is
the 6-bit type number. If the type number is non-zero, the second value is a
pointer to the C++ type info, otherwise the second value is null. Additionally,
CAF generates 32 bit \emph{type tokens}. These tokens are \emph{type hints}
that summarizes all types in a type-erased tuple. Two type-erased tuples are of
different type if they have different type tokens (the reverse is not true).
\clearpage
\subsection{Class \lstinline^type_erased_tuple^}
\textbf{Note}: Calling modifiers on a shared type-erased tuple is undefined
behavior.
\begin{center}
\begin{tabular}{ll}
\textbf{Types} & ~ \\
\hline
\lstinline^rtti_pair^ & \lstinline^std::pair<uint16_t, const std::type_info*>^ \\
\hline
~ & ~ \\ \textbf{Observers} & ~ \\
\hline
\lstinline^bool empty()^ & Returns whether this message is empty. \\
\hline
\lstinline^size_t size()^ & Returns the size of this message. \\
\hline
\lstinline^rtti_pair type(size_t pos)^ & Returns run-time type information for the nth element. \\
\hline
\lstinline^error save(serializer& x)^ & Writes the tuple to \lstinline^x^. \\
\hline
\lstinline^error save(size_t n, serializer& x)^ & Writes the nth element to \lstinline^x^. \\
\hline
\lstinline^const void* get(size_t n)^ & Returns a const pointer to the nth element. \\
\hline
\lstinline^std::string stringify()^ & Returns a string representation of the tuple. \\
\hline
\lstinline^std::string stringify(size_t n)^ & Returns a string representation of the nth element. \\
\hline
\lstinline^bool matches(size_t n, rtti_pair)^ & Checks whether the nth element has given type. \\
\hline
\lstinline^bool shared()^ & Checks whether more than one reference to the data exists. \\
\hline
\lstinline^bool match_element<T>(size_t n)^ & Checks whether element \lstinline^n^ has type \lstinline^T^. \\
\hline
\lstinline^bool match_elements<Ts...>()^ & Checks whether this message has the types \lstinline^Ts...^. \\
\hline
\lstinline^const T& get_as<T>(size_t n)^ & Returns a const reference to the nth element. \\
\hline
~ & ~ \\ \textbf{Modifiers} & ~ \\
\hline
\lstinline^void* get_mutable(size_t n)^ & Returns a mutable pointer to the nth element. \\
\hline
\lstinline^T& get_mutable_as<T>(size_t n)^ & Returns a mutable reference to the nth element. \\
\hline
\lstinline^void load(deserializer& x)^ & Reads the tuple from \lstinline^x^. \\
\hline
\end{tabular}
\end{center}
\subsection{Class \lstinline^message^}
The class \lstinline^message^ includes all member functions of
\lstinline^type_erased_tuple^. However, calling modifiers is always guaranteed
to be safe. A \lstinline^message^ automatically detaches its content by copying
it from the shared data on mutable access. The class further adds the following
member functions over \lstinline^type_erased_tuple^. Note that
\lstinline^apply^ only detaches the content if a callback takes mutable
references as arguments.
\begin{center}
\begin{tabular}{ll}
\textbf{Observers} & ~ \\
\hline
\lstinline^message drop(size_t n)^ & Creates a new message with all but the first \lstinline^n^ values. \\
\hline
\lstinline^message drop_right(size_t n)^ & Creates a new message with all but the last \lstinline^n^ values. \\
\hline
\lstinline^message take(size_t n)^ & Creates a new message from the first \lstinline^n^ values. \\
\hline
\lstinline^message take_right(size_t n)^ & Creates a new message from the last \lstinline^n^ values. \\
\hline
\lstinline^message slice(size_t p, size_t n)^ & Creates a new message from \lstinline^[p, p + n)^. \\
\hline
\lstinline^message extract(message_handler)^ & See \sref{extract}. \\
\hline
\lstinline^message extract_opts(...)^ & See \sref{extract-opts}. \\
\hline
~ & ~ \\ \textbf{Modifiers} & ~ \\
\hline
\lstinline^optional<message> apply(message_handler f)^ & Returns \lstinline^f(*this)^. \\
\hline
~ & ~ \\ \textbf{Operators} & ~ \\
\hline
\lstinline^message operator+(message x, message y)^ & Concatenates \lstinline^x^ and \lstinline^y^. \\
\hline
\lstinline^message& operator+=(message& x, message y)^ & Concatenates \lstinline^x^ and \lstinline^y^. \\
\hline
\end{tabular}
\end{center}
\clearpage
\subsection{Class \texttt{message\_builder}}
\begin{center}
\begin{tabular}{ll}
\textbf{Constructors} & ~ \\
\hline
\lstinline^(void)^ & Creates an empty message builder. \\
\hline
\lstinline^(Iter first, Iter last)^ & Adds all elements from range \lstinline^[first, last)^. \\
\hline
~ & ~ \\ \textbf{Observers} & ~ \\
\hline
\lstinline^bool empty()^ & Returns whether this message is empty. \\
\hline
\lstinline^size_t size()^ & Returns the size of this message. \\
\hline
\lstinline^message to_message( )^ & Converts the buffer to an actual message object. \\
\hline
\lstinline^append(T val)^ & Adds \lstinline^val^ to the buffer. \\
\hline
\lstinline^append(Iter first, Iter last)^ & Adds all elements from range \lstinline^[first, last)^. \\
\hline
\lstinline^message extract(message_handler)^ & See \sref{extract}. \\
\hline
\lstinline^message extract_opts(...)^ & See \sref{extract-opts}. \\
\hline
~ & ~ \\ \textbf{Modifiers} & ~ \\
\hline
\lstinline^optional<message>^ \lstinline^apply(message_handler f)^ & Returns \lstinline^f(*this)^. \\
\hline
\lstinline^message move_to_message()^ & Transfers ownership of its data to the new message. \\
\hline
\end{tabular}
\end{center}
\clearpage
\subsection{Extracting}
\label{extract}
The member function \lstinline^message::extract^ removes matched elements from
a message. x Messages are filtered by repeatedly applying a message handler to
the greatest remaining slice, whereas slices are generated in the sequence $[0,
size)$, $[0, size-1)$, $...$, $[1, size-1)$, $...$, $[size-1, size)$. Whenever
a slice is matched, it is removed from the message and the next slice starts at
the same index on the reduced message.
For example:
\begin{lstlisting}
auto msg = make_message(1, 2.f, 3.f, 4);
// remove float and integer pairs
auto msg2 = msg.extract({
[](float, float) { },
[](int, int) { }
});
assert(msg2 == make_message(1, 4));
\end{lstlisting}
Step-by-step explanation:
\begin{itemize}
\item Slice 1: \lstinline^(1, 2.f, 3.f, 4)^, no match
\item Slice 2: \lstinline^(1, 2.f, 3.f)^, no match
\item Slice 3: \lstinline^(1, 2.f)^, no match
\item Slice 4: \lstinline^(1)^, no match
\item Slice 5: \lstinline^(2.f, 3.f, 4)^, no match
\item Slice 6: \lstinline^(2.f, 3.f)^, \emph{match}; new message is \lstinline^(1, 4)^
\item Slice 7: \lstinline^(4)^, no match
\end{itemize}
Slice 7 is \lstinline^(4)^, i.e., does not contain the first element, because
the match on slice 6 occurred at index position 1. The function
\lstinline^extract^ iterates a message only once, from left to right. The
returned message contains the remaining, i.e., unmatched, elements.
\clearpage
\subsection{Extracting Command Line Options}
\label{extract-opts}
The class \lstinline^message^ also contains a convenience interface to
\lstinline^extract^ for parsing command line options: the member function
\lstinline^extract_opts^.
\begin{lstlisting}
int main(int argc, char** argv) {
uint16_t port;
string host = "localhost";
auto res = message_builder(argv + 1, argv + argc).extract_opts({
{"port,p", "set port", port},
{"host,H", "set host (default: localhost)", host},
{"verbose,v", "enable verbose mode"}
});
if (! res.error.empty()) {
// read invalid CLI arguments
cerr << res.error << endl;
return 1;
}
if (res.opts.count("help") > 0) {
// CLI arguments contained "-h", "--help", or "-?" (builtin);
cout << res.helptext << endl;
return 0;
}
if (! res.remainder.empty()) {
// res.remainder stors all extra arguments that weren't consumed
}
if (res.opts.count("verbose") > 0) {
// enable verbose mode
}
// ...
}
/*
Output of ./program_name -h:
Allowed options:
-p [--port] arg : set port
-H [--host] arg : set host (default: localhost)
-v [--verbose] : enable verbose mode
*/
\end{lstlisting}
\section{Migration Guides}
The guides in this section document all possibly breaking changes in the
library for that last versions of CAF.
\subsection{0.8 to 0.9}
Version 0.9 included a lot of changes and improvements in its implementation,
but it also made breaking changes to the API.
\paragraph{\lstinline^self^ has been removed}
~
This is the biggest library change since the initial release. The major problem
with this keyword-like identifier is that it must have a single type as it's
implemented as a thread-local variable. Since there are so many different kinds
of actors (event-based or blocking, untyped or typed), \lstinline^self^ needs
to perform type erasure at some point, rendering it ultimately useless. Instead
of a thread-local pointer, you can now use the first argument in functor-based
actors to "catch" the self pointer with proper type information.
\paragraph{\lstinline^actor_ptr^ has been replaced}
~
CAF now distinguishes between handles to actors, i.e.,
\lstinline^typed_actor<...>^ or simply \lstinline^actor^, and \emph{addresses}
of actors, i.e., \lstinline^actor_addr^. The reason for this change is that
each actor has a logical, (network-wide) unique address, which is used by the
networking layer of CAF. Furthermore, for monitoring or linking, the address
is all you need. However, the address is not sufficient for sending messages,
because it doesn't have any type information. The function
\lstinline^current_sender()^ now returns the \emph{address} of the sender. This
means that previously valid code such as \lstinline^send(current_sender(),...)^
will cause a compiler error. However, the recommended way of replying to
messages is to return the result from the message handler.
\paragraph{The API for typed actors is now similar to the API for untyped actors}
~
The APIs of typed and untyped actors have been harmonized. Typed actors can now
be published in the network and also use all operations untyped actors can.
\clearpage
\subsection{0.9 to 0.10 (\texttt{libcppa} to CAF)}
The first release under the new name CAF is an overhaul of the entire library.
Some classes have been renamed or relocated, others have been removed. The
purpose of this refactoring was to make the library easier to grasp and to make
its API more consistent. All classes now live in the namespace \texttt{caf} and
all headers have the top level folder \texttt{caf} instead of \texttt{cppa}.
For example, \texttt{cppa/actor.hpp} becomes \texttt{caf/actor.hpp}. Further,
the convenience header to get all parts of the user API is now
\texttt{"caf/all.hpp"}. The networking has been separated from the core
library. To get the networking components, simply include
\texttt{caf/io/all.hpp} and use the namespace \lstinline^caf::io^.
Version 0.10 still includes the header \texttt{cppa/cppa.hpp} to make the
transition process for users easier and to not break existing code right away.
The header defines the namespace \texttt{cppa} as an alias for \texttt{caf}.
Furthermore, it provides implementations or type aliases for renamed or removed
classes such as \lstinline^cow_tuple^. You won't get any warning about deprecated
headers with 0.10. However, we will add this warnings in the next library
version and remove deprecated code eventually.
Even when using the backwards compatibility header, the new library has
breaking changes. For instance, guard expressions have been removed entirely.
The reasoning behind this decision is that we already have projections to
modify the outcome of a match. Guard expressions add little expressive power to
the library but a whole lot of code that is hard to maintain in the long run
due to its complexity. Using projections to not only perform type conversions
but also to restrict values is the more natural choice.
\lstinline^any_tuple => message^
This type is only being used to pass a message from one actor to another.
Hence, \lstinline^message^ is the logical name.
\lstinline^partial_function => message_handler^
Technically, it still is a partial function. However, we wanted to put
emphasize on its use case.
\lstinline^cow_tuple => X^
We want to provide a streamlined, simple API. Shipping a full tuple abstraction
with the library does not fit into this philosophy. The removal of
\lstinline^cow_tuple^ implies the removal of related functions such as
\lstinline^tuple_cast^.
\lstinline^cow_ptr => X^
This pointer class is an implementation detail of \lstinline^message^ and
should not live in the global namespace in the first place. It also had the
wrong name, because it is intrusive.
\lstinline^X => message_builder^
This new class can be used to create messages dynamically. For example, the
content of a vector can be used to create a message using a series of
\lstinline^append^ calls.
\begin{lstlisting}
accept_handle, connection_handle, publish, remote_actor,
max_msg_size, typed_publish, typed_remote_actor, publish_local_groups,
new_connection_msg, new_data_msg, connection_closed_msg, acceptor_closed_msg
\end{lstlisting}
These classes concern I/O functionality and have thus been moved to
\lstinline^caf::io^
\subsection{0.10 to 0.11}
Version 0.11 introduced new, optional components. The core library itself,
however, mainly received optimizations and bugfixes with one exception: the
member function \lstinline^on_exit^ is no longer virtual. You can still provide
it to define a custom exit handler, but you must not use \lstinline^override^.
\subsection{0.11 to 0.12}
Version 0.12 removed two features:
\begin{itemize}
\item Type names are no longer demangled automatically. Hence, users must
explicitly pass the type name as first argument when using
\lstinline^announce^, i.e., \lstinline^announce<my_class>(...)^ becomes
\lstinline^announce<my_class>("my_class", ...)^.
\item Synchronous send blocks no longer support \lstinline^continue_with^. This
feature has been removed without substitution.
\end{itemize}
\subsection{0.12 to 0.13}
This release removes the (since 0.9 deprecated) \lstinline^cppa^ headers and
deprecates all \lstinline^*_send_tuple^ versions (simply use the function
without \lstinline^_tuple^ suffix). \lstinline^local_actor::on_exit^ once again
became virtual.
In case you were using the old \lstinline^cppa::options_description^ API, you
can migrate to the new API based on \lstinline^extract^ \see{extract-opts}.
Most importantly, version 0.13 slightly changes \lstinline^last_dequeued^ and
\lstinline^last_sender^. Both functions will now cause undefined behavior
(dereferencing a \lstinline^nullptr^) instead of returning dummy values when
accessed from outside a callback or after forwarding the current message.
Besides, these function names were not a good choice in the first place, since
``last'' implies accessing data received in the past. As a result, both
functions are now deprecated. Their replacements are named
\lstinline^current_message^ and \lstinline^current_sender^ \see{interface}.
\subsection{0.13 to 0.14}
The function \lstinline^timed_sync_send^ has been removed. It offered an
alternative way of defining message handlers, which is inconsistent with the
rest of the API.
The policy classes \lstinline^broadcast^, \lstinline^random^, and
\lstinline^round_robin^ in \lstinline^actor_pool^ were removed and replaced by
factory functions using the same name.
\clearpage
\subsection{0.14 to 0.15}
Version 0.15 replaces the singleton-based architecture with
\lstinline^actor_system^. Most of the free functions in namespace
\lstinline^caf^ are now member functions of \lstinline^actor_system^
\see{actor-system}. Likewise, most functions in namespace \lstinline^caf::io^
are now member functions of \lstinline^middleman^ \see{middleman}. The
structure of CAF applications has changed fundamentally with a focus on
configurability. Setting and fine-tuning the scheduler, changing parameters of
the middleman, etc. is now bundled in the class
\lstinline^actor_system_config^. The new configuration mechanism is also easily
extensible.
Patterns are now limited to the simple notation, because the advanced features
(1) are not implementable for statically typed actors, (2) are not portable to
Windows/MSVC, and (3) drastically impact compile times. Dropping this
functionality also simplifies the implementation and improves performance.
The \lstinline^blocking_api^ flag has been removed. All variants of
\emph{spawn} now auto-detect blocking actors.
\section{Middleman}
\label{middleman}
The middleman is the main component of the I/O module and enables distribution.
It transparently manages proxy actor instances representing remote actors,
maintains connections to other nodes, and takes care of serialization of
messages. Applications install a middleman by loading
\lstinline^caf::io::middleman^ as module~\see{system-config}. Users can include
\lstinline^"caf/io/all.hpp"^ to get access to all public classes of the I/O
module.
\subsection{Class \texttt{middleman}}
\begin{center}
\begin{tabular}{ll}
\textbf{Remoting} & ~ \\
\hline
\lstinline^expected<uint16> open(uint16, const char*, bool)^ & See~\sref{remoting}. \\
\hline
\lstinline^expected<uint16> publish(T, uint16, const char*, bool)^ & See~\sref{remoting}. \\
\hline
\lstinline^expected<void> unpublish(T x, uint16)^ & See~\sref{remoting}. \\
\hline
\lstinline^expected<node_id> connect(std::string host, uint16_t port)^ & See~\sref{remoting}. \\
\hline
\lstinline^expected<T> remote_actor<T = actor>(string, uint16)^ & See~\sref{remoting}. \\
\hline
\lstinline^expected<T> spawn_broker(F fun, ...)^ & See~\sref{broker}. \\
\hline
\lstinline^expected<T> spawn_client(F, string, uint16, ...)^ & See~\sref{broker}. \\
\hline
\lstinline^expected<T> spawn_server(F, uint16, ...)^ & See~\sref{broker}. \\
\hline
\end{tabular}
\end{center}
\subsection{Publishing and Connecting}
\label{remoting}
The member function \lstinline^publish^ binds an actor to a given port, thereby
allowing other nodes to access it over the network.
\begin{lstlisting}
template <class T>
expected<uint16_t> middleman::publish(T x, uint16_t port,
const char* in = nullptr,
bool reuse_addr = false);
\end{lstlisting}
The first argument is a handle of type \lstinline^actor^ or
\lstinline^typed_actor<...>^. The second argument denotes the TCP port. The OS
will pick a random high-level port when passing 0. The third parameter
configures the listening address. Passing null will accept all incoming
connections (\lstinline^INADDR_ANY^). Finally, the flag \lstinline^reuse_addr^
controls the behavior when binding an IP address to a port, with the same
semantics as the BSD socket flag \lstinline^SO_REUSEADDR^. For example, with
\lstinline^reuse_addr = false^, binding two sockets to 0.0.0.0:42 and
10.0.0.1:42 will fail with \texttt{EADDRINUSE} since 0.0.0.0 includes 10.0.0.1.
With \lstinline^reuse_addr = true^ binding would succeed because 10.0.0.1 and
0.0.0.0 are not literally equal addresses.
The member function returns the bound port on success. Otherwise, an
\lstinline^error^ \see{error} is returned.
\begin{lstlisting}
template <class T>
expected<uint16_t> middleman::unpublish(T x, uint16_t port = 0);
\end{lstlisting}
The member function \lstinline^unpublish^ allows actors to close a port
manually. This is performed automatically if the published actor terminates.
Passing 0 as second argument closes all ports an actor is published to,
otherwise only one specific port is closed.
The function returns an \lstinline^error^ \see{error} if the actor was not
bound to given port.
\clearpage
\begin{lstlisting}
template<class T = actor>
expected<T> middleman::remote_actor(std::string host, uint16_t port);
\end{lstlisting}
After a server has published an actor with \lstinline^publish^, clients can
connect to the published actor by calling \lstinline^remote_actor^:
\begin{lstlisting}
// node A
auto ping = spawn(ping);
system.middleman().publish(ping, 4242);
// node B
auto ping = system.middleman().remote_actor("node A", 4242);
if (! ping) {
cerr << "unable to connect to node A: "
<< system.render(ping.error()) << std::endl;
} else {
self->send(*ping, ping_atom::value);
}
\end{lstlisting}
There is no difference between server and client after the connection phase.
Remote actors use the same handle types as local actors and are thus fully
transparent.
The function pair \lstinline^open^ and \lstinline^connect^ allows users to
connect CAF instances without remote actor setup. The function
\lstinline^connect^ returns a \lstinline^node_id^ that can be used for remote
spawning (see~\sref{remote-spawn}).
\subsection{Free Functions}
\label{free-remoting-functions}
The following free functions in the namespace \lstinline^caf::io^ avoid calling
the middleman directly. This enables users to easily switch between
communication backends as long as the interfaces have the same signatures. For
example, the (experimental) OpenSSL binding of CAF implements the same
functions in the namespace \lstinline^caf::openssl^ to easily switch between
encrypted and unencrypted communication.
\begin{center}
\begin{tabular}{ll}
\hline
\lstinline^expected<uint16> open(actor_system&, uint16, const char*, bool)^ & See~\sref{remoting}. \\
\hline
\lstinline^expected<uint16> publish(T, uint16, const char*, bool)^ & See~\sref{remoting}. \\
\hline
\lstinline^expected<void> unpublish(T x, uint16)^ & See~\sref{remoting}. \\
\hline
\lstinline^expected<node_id> connect(actor_system&, std::string host, uint16_t port)^ & See~\sref{remoting}. \\
\hline
\lstinline^expected<T> remote_actor<T = actor>(actor_system&, string, uint16)^ & See~\sref{remoting}. \\
\hline
\end{tabular}
\end{center}
\subsection{Transport Protocols \experimental}
\label{transport-protocols}
CAF communication uses TCP per default and thus the functions shown in the
middleman API above are related to TCP. There are two alternatives to plain
TCP: TLS via the OpenSSL module shortly discussed in
\sref{free-remoting-functions} and UDP.
UDP is integrated in the default multiplexer and BASP broker. Set the flag
\lstinline^middleman_enable_udp^ to true to enable it
(see~\sref{system-config}). This does not require you to disable TCP. Use
\lstinline^publish_udp^ and \lstinline^remote_actor_udp^ to establish
communication.
Communication via UDP is inherently unreliable and unordered. CAF reestablishes
order and drops messages that arrive late. Messages that are sent via datagrams
are limited to a maximum of 65.535 bytes which is used as a receive buffer size
by CAF. Note that messages that exceed the MTU are fragmented by IP and are
considered lost if a single fragment is lost. Optional reliability based on
retransmissions and messages slicing on the application layer are planned for
the future.
\section{OpenCL-based Actors}
CAF supports transparent integration of OpenCL functions.
\begin{lstlisting}
// opencl kernel for matrix multiplication;
// last parameter is, by convention, the output parameter
constexpr const char* kernel_source = R"__(
__kernel void matrix_mult(__global float* matrix1,
__global float* matrix2,
__global float* output) {
// we only use square matrices, hence: width == height
size_t size = get_global_size(0); // == get_global_size_(1);
size_t x = get_global_id(0);
size_t y = get_global_id(1);
float result = 0;
for (size_t idx = 0; idx < size; ++idx)
result += matrix1[idx + y * size] * matrix2[x + idx * size];
output[x + y * size] = result;
}
)__";
\end{lstlisting}
\section{Reference Counting}
\label{reference-counting}
Actors systems can span complex communication graphs that make it hard to
decide when actors are no longer needed. As a result, manually managing
lifetime of actors is merely impossible. For this reason, CAF implements a
garbage collection strategy for actors based on weak and strong reference
counts.
\subsection{Shared Ownership in C++}
The C++ standard library already offers \lstinline^shared_ptr^ and
\lstinline^weak_ptr^ to manage objects with complex shared ownership. The
standard implementation is a solid general purpose design that covers most use
cases. Weak and strong references to an object are stored in a \emph{control
block}. However, CAF uses a slightly different design. The reason for this is
twofold. First, we need the control block to store the identity of an actor.
Second, we wanted a design that requires less indirections, because actor
handles are used extensively copied for messaging, and this overhead adds up.
Before discussing the approach to shared ownership in CAF, we look at the
design of shared pointers in the C++ standard library.
\singlefig{shared_ptr}{Shared pointer design in the C++ standard library}{shared-ptr}
The figure above depicts the default memory layout when using shared pointers.
The control block is allocated separately from the data and thus stores a
pointer to the data. This is when using manually-allocated objects, for example
\lstinline^shared_ptr<int> iptr{new int}^. The benefit of this design is that
one can destroy \lstinline^T^ independently from its control block. While
irrelevant for small objects, it can become an issue for large objects.
Notably, the shared pointer stores two pointers internally. Otherwise,
dereferencing it would require to get the data location from the control block
first.
\singlefig{make_shared}{Memory layout when using \lstinline^std::make_shared^}{make-shared}
When using \lstinline^make_shared^ or \lstinline^allocate_shared^, the standard
library can store reference count and data in a single memory block as shown
above. However, \lstinline^shared_ptr^ still has to store two pointers, because
it is unaware where the data is allocated.
\singlefig{enable_shared_from_this}{Memory layout with \lstinline^std::enable_shared_from_this^}{enable-shared-from-this}
Finally, the design of the standard library becomes convoluted when an object
should be able to hand out a \lstinline^shared_ptr^ to itself. Classes must
inherit from \lstinline^std::enable_shared_from_this^ to navigate from an
object to its control block. This additional navigation path is required,
because \lstinline^std::shared_ptr^ needs two pointers. One to the data and one
to the control block. Programmers can still use \lstinline^make_shared^ for
such objects, in which case the object is again stored along with the control
block.
\subsection{Smart Pointers to Actors}
In CAF, we use a different approach than the standard library because (1) we
always allocate actors along with their control block, (2) we need additional
information in the control block, and (3) we can store only a single raw
pointer internally instead of the two raw pointers \lstinline^std::shared_ptr^
needs. The following figure summarizes the design of smart pointers to actors.
\singlefig{refcounting}{Shared pointer design in CAF}{actor-pointer}
CAF uses \lstinline^strong_actor_ptr^ instead of
\lstinline^std::shared_ptr<...>^ and \lstinline^weak_actor_ptr^ instead of
\lstinline^std::weak_ptr<...>^. Unlike the counterparts from the standard
library, both smart pointer types only store a single pointer.
Also, the control block in CAF is not a template and stores the identity of an
actor (\lstinline^actor_id^ plus \lstinline^node_id^). This allows CAF to
access this information even after an actor died. The control block fits
exactly into a single cache line (64 Bytes). This makes sure no \emph{false
sharing} occurs between an actor and other actors that have references to it.
Since the size of the control block is fixed and CAF \emph{guarantees} the
memory layout enforced by \lstinline^actor_storage^, CAF can compute the
address of an actor from the pointer to its control block by offsetting it by
64 Bytes. Likewise, an actor can compute the address of its control block.
The smart pointer design in CAF relies on a few assumptions about actor types.
Most notably, the actor object is placed 64 Bytes after the control block. This
starting address is cast to \lstinline^abstract_actor*^. Hence, \lstinline^T*^
must be convertible to \lstinline^abstract_actor*^ via
\lstinline^reinterpret_cast^. In practice, this means actor subclasses must not
use virtual inheritance, which is enforced in CAF with a
\lstinline^static_assert^.
\subsection{Strong and Weak References}
A \emph{strong} reference manipulates the \lstinline^strong refs^ counter as
shown above. An actor is destroyed if there are \emph{zero} strong references
to it. If two actors keep strong references to each other via member variable,
neither actor can ever be destroyed because they produce a cycle
\see{breaking-cycles}. Strong references are formed by
\lstinline^strong_actor_ptr^, \lstinline^actor^, and
\lstinline^typed_actor<...>^ \see{actor-reference}.
A \emph{weak} reference manipulates the \lstinline^weak refs^ counter. This
counter keeps track of how many references to the control block exist. The
control block is destroyed if there are \emph{zero} weak references to an actor
(which cannot occur before \lstinline^strong refs^ reached \emph{zero} as
well). No cycle occurs if two actors keep weak references to each other,
because the actor objects themselves can get destroyed independently from their
control block. A weak reference is only formed by \lstinline^actor_addr^
\see{actor-address}.
\subsection{Converting Actor References with \texttt{actor\_cast}}
\label{actor-cast}
The function \lstinline^actor_cast^ converts between actor pointers and
handles. The first common use case is to convert a \lstinline^strong_actor_ptr^
to either \lstinline^actor^ or \lstinline^typed_actor<...>^ before being able
to send messages to an actor. The second common use case is to convert
\lstinline^actor_addr^ to \lstinline^strong_actor_ptr^ to upgrade a weak
reference to a strong reference. Note that casting \lstinline^actor_addr^ to a
strong actor pointer or handle can result in invalid handles. The syntax for
\lstinline^actor_cast^ resembles builtin C++ casts. For example,
\lstinline^actor_cast<actor>(x)^ converts \lstinline^x^ to an handle of type
\lstinline^actor^.
\subsection{Breaking Cycles Manually}
\label{breaking-cycles}
Cycles can occur only when using class-based actors when storing references to
other actors via member variable. Stateful actors \see{stateful-actor} break
cycles by destroying the state when an actor terminates, \emph{before} the
destructor of the actor itself runs. This means an actor releases all
references to others automatically after calling \lstinline^quit^. However,
class-based actors have to break cycles manually, because references to others
are not released until the destructor of an actor runs. Two actors storing
references to each other via member variable produce a cycle and neither
destructor can ever be called.
Class-based actors can break cycles manually by overriding
\lstinline^on_exit()^ and calling \lstinline^destroy(x)^ on each
handle~\see{actor-handle}. Using a handle after destroying it is undefined
behavior, but it is safe to assign a new value to the handle.
%TODO: Add use case for the following casting scenario. There is one
%requirement of this design: `static_cast<abstract_actor*>(self)` must return
%the same pointer as `reinterpret_cast<abstract_actor*>(self)` for any actor
%`self`. Otherwise, our assumption that the actor object starts exactly 64
%Bytes after its control block would break. Luckily, this boils down to a
%single limitation in practice: User-defined actors must not use virtual
%inheritance. When trying to spawn actors that do make use of virtual
%inheritance, CAF generates a compile-time error: `"actor subtype has illegal
%memory alignment (probably due to virtual inheritance)"`.
\section{Registry}
\label{registry}
The actor registry in CAF keeps track of the number of running actors and
allows to map actors to their ID or a custom atom~\see{atom} representing a
name. The registry does \emph{not} contain all actors. Actors have to be stored
in the registry explicitly. Users can access the registry through an actor
system by calling \lstinline^system.registry()^. The registry stores actors
using \lstinline^strong_actor_ptr^ \see{actor-pointer}.
Users can use the registry to make actors system-wide available by name. The
middleman~\see{middleman} uses the registry to keep track of all actors known
to remote nodes in order to serialize and deserialize them. Actors are removed
automatically when they terminate.
It is worth mentioning that the registry is not synchronized between connected
actor system. Each actor system has its own, local registry in a distributed
setting.
\begin{center}
\begin{tabular}{ll}
\textbf{Types} & ~ \\
\hline
\lstinline^name_map^ & \lstinline^unordered_map<atom_value, strong_actor_ptr>^ \\
\hline
~ & ~ \\ \textbf{Observers} & ~ \\
\hline
\lstinline^strong_actor_ptr get(actor_id)^ & Returns the actor associated to given ID. \\
\hline
\lstinline^strong_actor_ptr get(atom_value)^ & Returns the actor associated to given name. \\
\hline
\lstinline^name_map named_actors()^ & Returns all name mappings. \\
\hline
\lstinline^size_t running()^ & Returns the number of currently running actors. \\
\hline
~ & ~ \\ \textbf{Modifiers} & ~ \\
\hline
\lstinline^void put(actor_id, strong_actor_ptr)^ & Maps an actor to its ID. \\
\hline
\lstinline^void erase(actor_id)^ & Removes an ID mapping from the registry. \\
\hline
\lstinline^void put(atom_value, strong_actor_ptr)^ & Maps an actor to a name. \\
\hline
\lstinline^void erase(atom_value)^ & Removes a name mapping from the registry. \\
\hline
\end{tabular}
\end{center}
\section{Remote Spawning of Actors \experimental}
\label{remote-spawn}
Remote spawning is an extension of the dynamic spawn using run-time type names
\see{add-custom-actor-type}. The following example assumes a typed actor handle
named \lstinline^calculator^ with an actor implementing this messaging
interface named "calculator".
\cppexample[125-143]{remoting/remote_spawn}
We first connect to a CAF node with \lstinline^middleman().connect(...)^. On
success, \lstinline^connect^ returns the node ID we need for
\lstinline^remote_spawn^. This requires the server to open a port with
\lstinline^middleman().open(...)^ or \lstinline^middleman().publish(...)^.
Alternatively, we can obtain the node ID from an already existing remote actor
handle---returned from \lstinline^remote_actor^ for example---via
\lstinline^hdl->node()^. After connecting to the server, we can use
\lstinline^middleman().remote_spawn<...>(...)^ to create actors remotely.
\section{Scheduler}
\label{scheduler}
The CAF runtime maps N actors to M threads on the local machine. Applications
build with CAF scale by decomposing tasks into many independent steps that are
spawned as actors. In this way, sequential computations performed by individual
actors are small compared to the total runtime of the application, and the
attainable speedup on multi-core hardware is maximized in agreement with
Amdahl's law.
Decomposing tasks implies that actors are often short-lived. Assigning a
dedicated thread to each actor would not scale well. Instead, CAF includes a
scheduler that dynamically assigns actors to a pre-dimensioned set of worker
threads. Actors are modeled as lightweight state machines. Whenever a
\emph{waiting} actor receives a message, it changes its state to \emph{ready}
and is scheduled for execution. CAF cannot interrupt running actors because it
is implemented in user space. Consequently, actors that use blocking system
calls such as I/O functions can suspend threads and create an imbalance or lead
to starvation. Such ``uncooperative'' actors can be explicitly detached by the
programmer by using the \lstinline^detached^ spawn option, e.g.,
\lstinline^system.spawn<detached>(my_actor_fun)^.
The performance of actor-based applications depends on the scheduling algorithm
in use and its configuration. Different application scenarios require different
trade-offs. For example, interactive applications such as shells or GUIs want
to stay responsive to user input at all times, while batch processing
applications demand only to perform a given task in the shortest possible time.
Aside from managing actors, the scheduler bridges actor and non-actor code. For
this reason, the scheduler distinguishes between external and internal events.
An external event occurs whenever an actor is spawned from a non-actor context
or an actor receives a message from a thread that is not under the control of
the scheduler. Internal events are send and spawn operations from scheduled
actors.
\subsection{Policies}
\label{scheduler-policy}
The scheduler consists of a single coordinator and a set of workers. The
coordinator is needed by the public API to bridge actor and non-actor contexts,
but is not necessarily an active software entity.
The scheduler of CAF is fully customizable by using a policy-based design. The
following class shows a \emph{concept} class that lists all required member
types and member functions. A policy provides the two data structures
\lstinline^coordinator_data^ and \lstinline^worker_data^ that add additional
data members to the coordinator and its workers respectively, e.g., work
queues. This grants developers full control over the state of the scheduler.
\begin{lstlisting}
struct scheduler_policy {
struct coordinator_data;
struct worker_data;
void central_enqueue(Coordinator* self, resumable* job);
void external_enqueue(Worker* self, resumable* job);
void internal_enqueue(Worker* self, resumable* job);
void resume_job_later(Worker* self, resumable* job);
resumable* dequeue(Worker* self);
void before_resume(Worker* self, resumable* job);
void after_resume(Worker* self, resumable* job);
void after_completion(Worker* self, resumable* job);
};
\end{lstlisting}
Whenever a new work item is scheduled---usually by sending a message to an idle
actor---, one of the functions \lstinline^central_enqueue^,
\lstinline^external_enqueue^, and \lstinline^internal_enqueue^ is called. The
first function is called whenever non-actor code interacts with the actor
system. For example when spawning an actor from \lstinline^main^. Its first
argument is a pointer to the coordinator singleton and the second argument is
the new work item---usually an actor that became ready. The function
\lstinline^external_enqueue^ is never called directly by CAF. It models the
transfer of a task to a worker by the coordinator or another worker. Its first
argument is the worker receiving the new task referenced in the second
argument. The third function, \lstinline^internal_enqueue^, is called whenever
an actor interacts with other actors in the system. Its first argument is the
current worker and the second argument is the new work item.
Actors reaching the maximum number of messages per run are re-scheduled with
\lstinline^resume_job_later^ and workers acquire new work by calling
\lstinline^dequeue^. The two functions \lstinline^before_resume^ and
\lstinline^after_resume^ allow programmers to measure individual actor runtime,
while \lstinline^after_completion^ allows to execute custom code whenever a
work item has finished execution by changing its state to \emph{done}, but
before it is destroyed. In this way, the last three functions enable developers
to gain fine-grained insight into the scheduling order and individual execution
times.
\subsection{Work Stealing}
\label{work-stealing}
The default policy in CAF is work stealing. The key idea of this algorithm is
to remove the bottleneck of a single, global work queue. The original
algorithm was developed for fully strict computations by Blumofe et al in 1994.
It schedules any number of tasks to \lstinline^P^ workers, where \lstinline^P^
is the number of processors available.
\singlefig{stealing}{Stealing of work items}{fig-stealing}
Each worker dequeues work items from an individual queue until it is drained.
Once this happens, the worker becomes a \emph{thief}. It picks one of the other
workers---usually at random---as a \emph{victim} and tries to \emph{steal} a
work item. As a consequence, tasks (actors) are bound to workers by default and
only migrate between threads as a result of stealing. This strategy minimizes
communication between threads and maximizes cache locality. Work stealing has
become the algorithm of choice for many frameworks. For example, Java's
Fork-Join (which is used by Akka), Intel's Threading Building Blocks, several
OpenMP implementations, etc.
CAF uses a double-ended queue for its workers, which is synchronized with two
spinlocks. One downside of a decentralized algorithm such as work stealing is,
that idle states are hard to detect. Did only one worker run out of work items
or all? Since each worker has only local knowledge, it cannot decide when it
could safely suspend itself. Likewise, workers cannot resume if new job items
arrived at one or more workers. For this reason, CAF uses three polling
intervals. Once a worker runs out of work items, it tries to steal items from
others. First, it uses the \emph{aggressive} polling interval. It falls back to
a \emph{moderate} interval after a predefined number of trials. After another
predefined number of trials, it will finally use a \emph{relaxed} interval.
Per default, the \emph{aggressive} strategy performs 100 steal attempts with no
sleep interval in between. The \emph{moderate} strategy tries to steal 500
times with 50 microseconds sleep between two steal attempts. Finally, the
\emph{relaxed} strategy runs indefinitely but sleeps for 10 milliseconds
between two attempts. These defaults can be overridden via system config at
startup~\see{system-config}.
\subsection{Work Sharing}
\label{work-sharing}
Work sharing is an alternative scheduler policy in CAF that uses a single,
global work queue. This policy uses a mutex and a condition variable on the
central queue. Thus, the policy supports only limited concurrency but does not
need to poll. Using this policy can be a good fit for low-end devices where
power consumption is an important metric.
% TODO: profiling section
\section{Streaming\experimental}
\label{streaming}
Streams in CAF describe data flow between actors. We are not aiming to provide
functionality similar to Apache projects like Spark, Flink or Storm. Likewise,
we have different goals than APIs such as RxJava, Reactive Streams, etc.
Streams complement asynchronous messages, request/response communication and
publish/subscribe in CAF. In a sense, actor streams in CAF are a building
block that users could leverage for building feature-complete stream
computation engines or reactive high-level Big Data APIs.
A stream establishes a logical channel between two or more actors for
exchanging a potentially unbound sequence of values. This channel uses demand
signaling to guarantee that senders cannot overload receivers.
\singlefig{stream}{Streaming Concept}{stream}
Streams are directed and data flows only \emph{downstream}, i.e., from sender
(source) to receiver (sink). Establishing a stream requires a handshake in
order to initialize required state and signal initial demand.
\singlefig{stream-roles}{Streaming Roles}{stream-roles}
CAF distinguishes between three roles in a stream: (1) a \emph{source} creates
streams and generates data, (2) a \emph{stage} transforms or filters data, and
(3) a \emph{sink} terminates streams by consuming data.
We usually draw streams as pipelines for simplicity. However, sources can have
any number of outputs (downstream actors). Likewise, sinks can have any number
of inputs (upstream actors) and stages can multiplex N inputs to M outputs.
Hence, streaming topologies in CAF support arbitrary complexity with forks and
joins.
\subsection{Stream Managers}
Streaming-related messages are handled separately. Under the hood, actors
delegate to \emph{stream managers} that in turn allow customization of their
behavior with \emph{drivers} and \emph{downstream managers}.
\singlefig{stream-manager}{Internals of Stream Managers}{fig-stream-manager}
Users usually can skip implementing driver classes and instead use the
lambda-based interface showcased in the following sections. Drivers implement
the streaming logic by taking inputs from upstream actors and pushing data to
the downstream manager. A source has no input buffer. Hence, drivers only
provide a \emph{generator} function that downstream managers call according to
demand.
A downstream manager is responsible for dispatching data to downstream actors.
The default implementation broadcasts data, i.e., all downstream actors receive
the same data. The downstream manager can also perform any sort multi- or
anycast. For example, a load-balancer would use an anycast policy to dispatch
data to the next available worker.
\clearpage
\subsection{Defining Sources}
\cppexample[17-52]{streaming/integer_stream}
The simplest way to defining a source is to use the \lstinline^make_source^
function and pass it three arguments: \emph{initializer} for the state,
\emph{generator} for producing values, and \emph{predicate} for signaling the
end of the stream.
\clearpage
\subsection{Defining Stages}
\cppexample[54-87]{streaming/integer_stream}
The function \lstinline^make_stage^ also takes three lambdas but additionally
the received input stream handshake as first argument. Instead of a predicate,
\lstinline^make_stage^ only takes a finalizer, since the stage does not produce
data on its own and a stream terminates if no more sources exist.
\clearpage
\subsection{Defining Sinks}
\cppexample[89-120]{streaming/integer_stream}
The function \lstinline^make_sink^ is similar to \lstinline^make_stage^, except
that is does not produce outputs.
\clearpage
\subsection{Initiating Streams}
\cppexample[133-139]{streaming/integer_stream}
In our example, we always have a source \lstinline^int_source^ and a sink
\lstinline^int_sink^ with an optional stage \lstinline^int_selector^. Sending
\lstinline^open_atom^ to the source initiates the stream and the source will
respond with a stream handshake.
Using the actor composition in CAF (\lstinline^snk * src^ reads \emph{sink
after source}) allows us to redirect the stream handshake we send in
\lstinline^caf_main^ to the sink (or to the stage and then from the stage to
the sink).
\section{Type Inspection (Serialization and String Conversion)}
\label{type-inspection}
CAF is designed with distributed systems in mind. Hence, all message types
must be serializable and need a platform-neutral, unique name that is
configured at startup \see{add-custom-message-type}. Using a message type that
is not serializable causes a compiler error \see{unsafe-message-type}. CAF
serializes individual elements of a message by using the inspection API. This
API allows users to provide code for serialization as well as string conversion
with a single free function. The signature for a class \lstinline^my_class^ is
always as follows:
\begin{lstlisting}
template <class Inspector>
typename Inspector::result_type inspect(Inspector& f, my_class& x) {
return f(...);
}
\end{lstlisting}
The function \lstinline^inspect^ passes meta information and data fields to the
variadic call operator of the inspector. The following example illustrates an
implementation for \lstinline^inspect^ for a simple POD struct.
\cppexample[23-33]{custom_type/custom_types_1}
The inspector recursively inspects all data fields and has builtin support for
(1) \lstinline^std::tuple^, (2) \lstinline^std::pair^, (3) C arrays, (4) any
container type with \lstinline^x.size()^, \lstinline^x.empty()^,
\lstinline^x.begin()^ and \lstinline^x.end()^.
We consciously made the inspect API as generic as possible to allow for
extensibility. This allows users to use CAF's types in other contexts, to
implement parsers, etc.
\subsection{Inspector Concept}
The following concept class shows the requirements for inspectors. The
placeholder \lstinline^T^ represents any user-defined type. For example,
\lstinline^error^ when performing I/O operations or some integer type when
implementing a hash function.
\begin{lstlisting}
Inspector {
using result_type = T;
if (inspector only requires read access to the state of T)
static constexpr bool reads_state = true;
else
static constexpr bool writes_state = true;
template <class... Ts>
result_type operator()(Ts&&...);
}
\end{lstlisting}
A saving \lstinline^Inspector^ is required to handle constant lvalue and rvalue
references. A loading \lstinline^Inspector^ must only accept mutable lvalue
references to data fields, but still allow for constant lvalue references and
rvalue references to annotations.
\subsection{Annotations}
Annotations allow users to fine-tune the behavior of inspectors by providing
addition meta information about a type. All annotations live in the namespace
\lstinline^caf::meta^ and derive from \lstinline^caf::meta::annotation^. An
inspector can query whether a type \lstinline^T^ is an annotation with
\lstinline^caf::meta::is_annotation<T>::value^. Annotations are passed to the
call operator of the inspector along with data fields. The following list shows
all annotations supported by CAF:
\begin{itemize}
\item \lstinline^type_name(n)^: Display type name as \lstinline^n^ in
human-friendly output (position before data fields).
\item \lstinline^hex_formatted()^: Format the following data field in hex
format.
\item \lstinline^omittable()^: Omit the following data field in human-friendly
output.
\item \lstinline^omittable_if_empty()^: Omit the following data field if it is
empty in human-friendly output.
\item \lstinline^omittable_if_none()^: Omit the following data field if it
equals \lstinline^none^ in human-friendly output.
\item \lstinline^save_callback(f)^: Call \lstinline^f^ when serializing
(position after data fields).
\item \lstinline^load_callback(f)^: Call \lstinline^f^ after deserializing all
data fields (position after data fields).
\end{itemize}
\subsection{Backwards and Third-party Compatibility}
CAF evaluates common free function other than \lstinline^inspect^ in order to
simplify users to integrate CAF into existing code bases.
Serializers and deserializers call user-defined \lstinline^serialize^
functions. Both types support \lstinline^operator&^ as well as
\lstinline^operator()^ for individual data fields. A \lstinline^serialize^
function has priority over \lstinline^inspect^.
When converting a user-defined type to a string, CAF calls user-defined
\lstinline^to_string^ functions and prefers those over \lstinline^inspect^.
\subsection{Whitelisting Unsafe Message Types}
\label{unsafe-message-type}
Message types that are not serializable cause compile time errors when used in
actor communication. When using CAF for concurrency only, this errors can be
suppressed by whitelisting types with
\lstinline^CAF_ALLOW_UNSAFE_MESSAGE_TYPE^. The macro is defined as follows.
% TODO: expand example here\cppexample[linerange={50-54}]{../../libcaf_core/caf/allowed_unsafe_message_type.hpp}
\clearpage
\subsection{Splitting Save and Load Operations}
If loading and storing cannot be implemented in a single function, users can
query whether the inspector is loading or storing. For example, consider the
following class \lstinline^foo^ with getter and setter functions and no public
access to its members.
\cppexample[20-49]{custom_type/custom_types_3}
\clearpage
Since there is no access to the data fields \lstinline^a_^ and \lstinline^b_^
(and assuming no changes to \lstinline^foo^ are possible), we need to split our
implementation of \lstinline^inspect^ as shown below.
\cppexample[76-103]{custom_type/custom_types_3}
The purpose of the scope guard in the example above is to write the content of
the temporaries back to \lstinline^foo^ at scope exit automatically. Storing
the result of \lstinline^f(...)^ in a temporary first and then writing the
changes to \lstinline^foo^ is not possible, because \lstinline^f(...)^ can
return \lstinline^void^.
\section{Using \texttt{aout} -- A Concurrency-safe Wrapper for \texttt{cout}}
When using \lstinline^cout^ from multiple actors, output often appears
interleaved. Moreover, using \lstinline^cout^ from multiple actors -- and thus
from multiple threads -- in parallel should be avoided regardless, since the
standard does not guarantee a thread-safe implementation.
By replacing \texttt{std::cout} with \texttt{caf::aout}, actors can achieve a
concurrency-safe text output. The header \lstinline^caf/all.hpp^ also defines
overloads for \texttt{std::endl} and \texttt{std::flush} for \lstinline^aout^,
but does not support the full range of ostream operations (yet). Each write
operation to \texttt{aout} sends a message to a `hidden' actor. This actor only
prints lines, unless output is forced using \lstinline^flush^. The example
below illustrates printing of lines of text from multiple actors (in random
order).
\cppexample{aout}
\section{Utility}
\label{utility}
CAF includes a few utility classes that are likely to be part of C++
eventually (or already are in newer versions of the standard). However, until
these classes are part of the standard library on all supported compilers, we
unfortunately have to maintain our own implementations.
\subsection{Class \lstinline^optional^}
\label{optional}
Represents a value that may or may not exist.
\begin{center}
\begin{tabular}{ll}
\textbf{Constructors} & ~ \\
\hline
\lstinline^(T value)^ & Constructs an object with a value. \\
\hline
\lstinline^(none_t = none)^ & Constructs an object without a value. \\
\hline
~ & ~ \\ \textbf{Observers} & ~ \\
\hline
\lstinline^explicit operator bool()^ & Checks whether the object contains a value. \\
\hline
\lstinline^T* operator->()^ & Accesses the contained value. \\
\hline
\lstinline^T& operator*()^ & Accesses the contained value. \\
\hline
\end{tabular}
\end{center}
\subsection{Class \lstinline^expected^}
Represents the result of a computation that \emph{should} return a value. If no
value could be produced, the \lstinline^expected<T>^ contains an
\lstinline^error^ \see{error}.
\begin{center}
\begin{tabular}{ll}
\textbf{Constructors} & ~ \\
\hline
\lstinline^(T value)^ & Constructs an object with a value. \\
\hline
\lstinline^(error err)^ & Constructs an object with an error. \\
\hline
~ & ~ \\ \textbf{Observers} & ~ \\
\hline
\lstinline^explicit operator bool()^ & Checks whether the object contains a value. \\
\hline
\lstinline^T* operator->()^ & Accesses the contained value. \\
\hline
\lstinline^T& operator*()^ & Accesses the contained value. \\
\hline
\lstinline^error& error()^ & Accesses the contained error. \\
\hline
\end{tabular}
\end{center}
\subsection{Constant \lstinline^unit^}
The constant \lstinline^unit^ of type \lstinline^unit_t^ is the equivalent of
\lstinline^void^ and can be used to initialize \lstinline^optional<void>^ and
\lstinline^expected<void>^.
\subsection{Constant \lstinline^none^}
The constant \lstinline^none^ of type \lstinline^none_t^ can be used to
initialize an \lstinline^optional<T>^ to represent ``nothing''.
# -*- coding: utf-8 -*-
#
# CAF documentation build configuration file, created by
# sphinx-quickstart on Fri Jun 3 11:27:36 2016.
#
# This file is execfile()d with the current directory set to its
# containing dir.
#
# Note that not all possible configuration values are present in this
# autogenerated file.
#
# All configuration values have a default; values that are commented out
# serve to show the default.
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
#
# import os
# import sys
# sys.path.insert(0, os.path.abspath('.'))
# -- General configuration ------------------------------------------------
# If your documentation needs a minimal Sphinx version, state it here.
#
# needs_sphinx = '1.0'
import sphinx_rtd_theme
# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones.
extensions = []
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
# The suffix(es) of source filenames.
# You can specify multiple suffix as a list of string:
#
# source_suffix = ['.rst', '.md']
source_suffix = '.rst'
# The encoding of source files.
#
# source_encoding = 'utf-8-sig'
# The master toctree document.
master_doc = 'index'
# General information about the project.
project = u'CAF'
copyright = u'2016, Dominik Charousset'
author = u'Dominik Charousset'
# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
# built documents.
#
# The short X.Y version.
version = u'0.16.0'
# The full version, including alpha/beta/rc tags.
release = u'0.16.0'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
#
# This is also used if you do content translation via gettext catalogs.
# Usually you set "language" from the command line for these cases.
language = None
# There are two options for replacing |today|: either, you set today to some
# non-false value, then it is used:
#
# today = ''
#
# Else, today_fmt is used as the format for a strftime call.
#
# today_fmt = '%B %d, %Y'
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
# This patterns also effect to html_static_path and html_extra_path
exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
# The reST default role (used for this markup: `text`) to use for all
# documents.
#
# default_role = None
# If true, '()' will be appended to :func: etc. cross-reference text.
#
# add_function_parentheses = True
# If true, the current module name will be prepended to all description
# unit titles (such as .. function::).
#
# add_module_names = True
# If true, sectionauthor and moduleauthor directives will be shown in the
# output. They are ignored by default.
#
# show_authors = False
# The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'sphinx'
highlight_language = 'C++'
# A list of ignored prefixes for module index sorting.
# modindex_common_prefix = []
# If true, keep warnings as "system message" paragraphs in the built documents.
# keep_warnings = False
# If true, `todo` and `todoList` produce output, else they produce nothing.
todo_include_todos = False
# -- Options for HTML output ----------------------------------------------
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
#
html_theme = 'sphinx_rtd_theme'
# Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the
# documentation.
#
# html_theme_options = {}
# Add any paths that contain custom themes here, relative to this directory.
html_theme_path = [sphinx_rtd_theme.get_html_theme_path()]
# The name for this set of Sphinx documents.
# "<project> v<release> documentation" by default.
#
# html_title = u'CAF v0.15'
# A shorter title for the navigation bar. Default is the same as html_title.
#
# html_short_title = None
# The name of an image file (relative to this directory) to place at the top
# of the sidebar.
#
# html_logo = None
# The name of an image file (relative to this directory) to use as a favicon of
# the docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
# pixels large.
#
# html_favicon = None
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ['_static']
# Add any extra paths that contain custom files (such as robots.txt or
# .htaccess) here, relative to this directory. These files are copied
# directly to the root of the documentation.
#
# html_extra_path = []
# If not None, a 'Last updated on:' timestamp is inserted at every page
# bottom, using the given strftime format.
# The empty string is equivalent to '%b %d, %Y'.
#
# html_last_updated_fmt = None
# If true, SmartyPants will be used to convert quotes and dashes to
# typographically correct entities.
#
# html_use_smartypants = True
# Custom sidebar templates, maps document names to template names.
#
# html_sidebars = {}
# Additional templates that should be rendered to pages, maps page names to
# template names.
#
# html_additional_pages = {}
# If false, no module index is generated.
#
# html_domain_indices = True
# If false, no index is generated.
#
# html_use_index = True
# If true, the index is split into individual pages for each letter.
#
# html_split_index = False
# If true, links to the reST sources are added to the pages.
#
# html_show_sourcelink = True
# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
#
# html_show_sphinx = True
# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
#
# html_show_copyright = True
# If true, an OpenSearch description file will be output, and all pages will
# contain a <link> tag referring to it. The value of this option must be the
# base URL from which the finished HTML is served.
#
# html_use_opensearch = ''
# This is the file name suffix for HTML files (e.g. ".xhtml").
# html_file_suffix = None
# Language to be used for generating the HTML full-text search index.
# Sphinx supports the following languages:
# 'da', 'de', 'en', 'es', 'fi', 'fr', 'hu', 'it', 'ja'
# 'nl', 'no', 'pt', 'ro', 'ru', 'sv', 'tr', 'zh'
#
# html_search_language = 'en'
# A dictionary with options for the search language support, empty by default.
# 'ja' uses this config value.
# 'zh' user can custom change `jieba` dictionary path.
#
# html_search_options = {'type': 'default'}
# The name of a javascript file (relative to the configuration directory) that
# implements a search results scorer. If empty, the default will be used.
#
# html_search_scorer = 'scorer.js'
# Output file base name for HTML help builder.
htmlhelp_basename = 'CAFdoc'
# -- Options for LaTeX output ---------------------------------------------
latex_elements = {
# The paper size ('letterpaper' or 'a4paper').
#
# 'papersize': 'letterpaper',
# The font size ('10pt', '11pt' or '12pt').
#
# 'pointsize': '10pt',
# Additional stuff for the LaTeX preamble.
#
# 'preamble': '',
# Latex figure (float) alignment
#
# 'figure_align': 'htbp',
}
# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title,
# author, documentclass [howto, manual, or own class]).
latex_documents = [
(master_doc, 'CAF.tex', u'CAF Documentation',
u'Dominik Charousset', 'manual'),
]
# The name of an image file (relative to this directory) to place at the top of
# the title page.
#
# latex_logo = None
# For "manual" documents, if this is true, then toplevel headings are parts,
# not chapters.
#
# latex_use_parts = False
# If true, show page references after internal links.
#
# latex_show_pagerefs = False
# If true, show URL addresses after external links.
#
# latex_show_urls = False
# Documents to append as an appendix to all manuals.
#
# latex_appendices = []
# If false, no module index is generated.
#
# latex_domain_indices = True
# -- Options for manual page output ---------------------------------------
# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
man_pages = [
(master_doc, 'caf', u'CAF Documentation',
[author], 1)
]
# If true, show URL addresses after external links.
#
# man_show_urls = False
# -- Options for Texinfo output -------------------------------------------
# Grouping the document tree into Texinfo files. List of tuples
# (source start file, target name, title, author,
# dir menu entry, description, category)
texinfo_documents = [
(master_doc, 'CAF', u'CAF Documentation',
author, 'CAF', 'One line description of project.',
'Miscellaneous'),
]
# Documents to append as an appendix to all manuals.
#
# texinfo_appendices = []
# If false, no module index is generated.
#
# texinfo_domain_indices = True
# How to display URL addresses: 'footnote', 'no', or 'inline'.
#
# texinfo_show_urls = 'footnote'
# If true, do not generate a @detailmenu in the "Top" node's menu.
#
# texinfo_no_detailmenu = False
#!/bin/bash
blacklist="manual.tex variables.tex colors.tex newcommands.tex"
inBlacklist() {
for e in $blacklist; do
[[ "$e" == "$1" ]] && return 0
done
return 1
}
for i in *.tex ; do
if inBlacklist $i ; then
continue
fi
out_file=$(basename $i .tex)
echo "$i => $out_file"
cat colors.tex variables.tex newcommands.tex $i | ./explode_lstinputlisting.py | pandoc --filter=$PWD/filter.py --wrap=none --listings -f latex -o ${out_file}.rst
done
sphinx-build -b html . html
#!/usr/bin/env python
import sys
import re
def parse_range(astr):
result = set()
for part in astr.split(','):
x = part.split('-')
result.update(range(int(x[0]), int(x[-1]) + 1))
return sorted(result)
def print_listing(line_range, fname):
print('\\begin{lstlisting}')
if not line_range:
with open(fname, 'r') as fin:
sys.stdout.write(fin.read())
else:
with open(fname) as mfile:
for num, line in enumerate(mfile, 1):
if num in line_range:
sys.stdout.write(line)
print('\\end{lstlisting}')
def cppexample(line_range, fname):
print_listing(line_range, '../../examples/{0}.cpp'.format(fname))
def iniexample(line_range, fname):
print_listing(line_range, '../../examples/{0}.ini'.format(fname))
def sourcefile(line_range, fname):
print_listing(line_range, '../../{0}'.format(fname))
rx = re.compile(r"\\(cppexample|iniexample|sourcefile)(?:\[(.+)\])?{(.+)}")
for line in sys.stdin:
m = rx.match(line)
if not m:
sys.stdout.write(line)
else:
locals()[m.group(1)](parse_range(m.group(2)), m.group(3))
.. include:: index_header.rst
.. toctree::
:maxdepth: 2
:caption: Core Library
Introduction
FirstSteps
TypeInspection
MessageHandlers
Actors
MessagePassing
Scheduler
Registry
ReferenceCounting
Error
ConfiguringActorApplications
Messages
GroupCommunication
ManagingGroupsOfWorkers
Streaming
.. toctree::
:maxdepth: 2
:caption: I/O Library
NetworkTransparency
Brokers
RemoteSpawn
.. toctree::
:maxdepth: 2
:caption: Appendix
FAQ
Utility
CommonPitfalls
UsingAout
MigrationGuides
.. include:: index_footer.rst
Version Information
===================
This version of the Manual was automatically generated from CAF commit
`903f801c <https://github.com/actor-framework/actor-framework/commit/903f801c>`_
and Manual commit
`a4604f9 <https://github.com/actor-framework/manual/commit/a4604f9>`_.
CAF User Manual
===============
**C++ Actor Framework** version 0.16.0.
Contents
========
#!/usr/bin/env python
# Generates the content for an index.rst file
# from the content of a manual.tex file
import re
import sys
def print_header():
sys.stdout.write(".. include:: index_header.rst\n")
def print_footer():
sys.stdout.write("\n.. include:: index_footer.rst\n")
part_rx = re.compile(r"\\part{(.+)}")
include_rx = re.compile(r"\\include{(.+)}")
print_header()
for line in sys.stdin:
m = part_rx.match(line)
if m:
sys.stdout.write("\n.. toctree::\n"
" :maxdepth: 2\n"
" :caption: ")
sys.stdout.write(m.group(1))
sys.stdout.write("\n\n")
continue
m = include_rx.match(line)
if m:
sys.stdout.write(" ")
sys.stdout.write(m.group(1))
sys.stdout.write("\n")
print_footer()
\documentclass[%
a4paper,% % DIN A4
oneside,% % einseitiger Druck
12pt,% % 12pt Schriftgröße
]{article}
\usepackage[utf8]{inputenc}
% include required packages
\usepackage{array}
\usepackage{capt-of}
\usepackage{color}
\usepackage{float}
\usepackage{graphicx}
\usepackage{hyperref}
\usepackage{listings}
\usepackage{multicol}
\usepackage{tabularx}
\usepackage{url}
\usepackage{xifthen}
\usepackage{xspace}
% font setup
\usepackage[scaled=.90]{helvet}
\usepackage{cmbright}
\usepackage{courier}
\usepackage{txfonts}
% paragraph settings
\parindent 0pt
\parskip 8pt
\pretolerance=150
\tolerance=500
\emergencystretch=\maxdimen
\hbadness=10000
\pagenumbering{arabic}
% custom colors
\definecolor{lightgrey}{rgb}{0.9,0.9,0.9}
\definecolor{lightblue}{rgb}{0,0,1}
\definecolor{grey}{rgb}{0.5,0.5,0.5}
\definecolor{blue}{rgb}{0,0,1}
\definecolor{violet}{rgb}{0.5,0,0.5}
\definecolor{darkred}{rgb}{0.5,0,0}
\definecolor{darkblue}{rgb}{0,0,0.5}
\definecolor{darkgreen}{rgb}{0,0.5,0}
\input{tex/variables}
\title{%
\texttt{\huge{\textbf{CAF}}}\\
~\\
The C++ Actor Framework\\
~\\
~\\
~\\
User Manual\\
\normalsize{Version \cafrelease}\\
~\\
~\\
\tiny SHA \cafsha
\vfill}
\author{Dominik Charousset}
\date{\today}
% page setup
\setlength{\voffset}{-1in}
\setlength{\hoffset}{-0.75in}
\addtolength{\textwidth}{1.5in}
\addtolength{\textheight}{2in}
\setlength{\headheight}{15pt}
% include paragraphs in TOC
\setcounter{tocdepth}{3}
% more compact itemize
\newenvironment{itemize*}%
{\begin{itemize}%
\setlength{\itemsep}{0pt}%
\setlength{\parskip}{0pt}}%
{\end{itemize}}
\begin{document}
\maketitle\thispagestyle{empty}
\pagestyle{empty}
\clearpage
\tableofcontents
\clearpage
\setcounter{page}{1}
\pagestyle{plain}
% directory layout
\graphicspath{{pdf/}}
% custom commands
\newcommand{\sref}[1]{\S\,\ref{#1}}
\newcommand{\see}[1]{(see~\sref{#1})}
\newcommand{\singlefig}[3]{
\begin{figure}[H]
\centering
\includegraphics[width=.6\columnwidth]{#1}
\caption{#2}
\label{#3}
\end{figure}
}
\newcommand{\experimental}{
{\color{darkred}\textsuperscript{experimental}}
}
\newcommand{\cppexample}[2][]{%
\ifthenelse{\isempty{#1}}%
{\lstinputlisting{../../examples/#2.cpp}}%
{\lstinputlisting[language=C++,linerange={#1}]{../../examples/#2.cpp}}%
}
\newcommand{\iniexample}[2][]{%
\ifthenelse{\isempty{#1}}%
{\lstinputlisting[language=ini]{../../examples/#2.ini}}%
{\lstinputlisting[language=ini,linerange={#1}]{../../examples/#2.ini}}%
}
\newcommand{\sourcefile}[2][]{%
\ifthenelse{\isempty{#1}}%
{\lstinputlisting[language=C++]{../../#2}}%
{\lstinputlisting[language=C++,linerange={#1}]{../../#2}}%
}
% highlight for INI file syntax
\lstdefinelanguage{ini}{%
basicstyle=\ttfamily\footnotesize,%
% columns=fullflexible,%
morecomment=[s][\color{blue}]{[}{]},%
morecomment=[l]{;},%
morecomment=[s]{<}{>},%
morestring=[b]",%
morestring=[b]',%
commentstyle=\color{violet},%
morekeywords={},%
otherkeywords={=,false,true},%
keywordstyle=\color{blue},%
stringstyle=\color{darkgreen},%
}
% code listings setup
\lstset{%
language=C++,%
morekeywords={constexpr,nullptr,size_t,uint32_t,assert,override,final},%
basicstyle=\ttfamily\footnotesize,%
sensitive=true,%
keywordstyle=\color{blue},%
stringstyle=\color{darkgreen},%
commentstyle=\color{violet},%
showstringspaces=false,%
tabsize=2,%
frame=leftline,
rulecolor=\color{lightblue},
xleftmargin=20pt,
}
\lstset{
numberstyle=\tiny,
numbers=left,
numbersep=10pt,
xleftmargin=20pt,
%framesep=4.5mm,
%framexleftmargin=2.5mm,
framexleftmargin=5pt,
framesep=15pt,
fillcolor=\color{lightgrey},
}
% content
\part{Core Library}
\include{tex/Introduction}
\include{tex/FirstSteps}
\include{tex/TypeInspection}
\include{tex/MessageHandlers}
\include{tex/Actors}
\include{tex/MessagePassing}
\include{tex/Scheduler}
\include{tex/Registry}
\include{tex/ReferenceCounting}
\include{tex/Error}
\include{tex/ConfiguringActorApplications}
\include{tex/Messages}
\include{tex/GroupCommunication}
\include{tex/ManagingGroupsOfWorkers}
\include{tex/Streaming}
\part{I/O Library}
\include{tex/NetworkTransparency}
\include{tex/Brokers}
\include{tex/RemoteSpawn}
\part{Appendix}
\include{tex/FAQ}
\include{tex/Utility}
\include{tex/CommonPitfalls}
\include{tex/UsingAout}
\include{tex/MigrationGuides}
\end{document}
...@@ -18,7 +18,7 @@ ...@@ -18,7 +18,7 @@
// This file is partially included in the manual, do not modify // This file is partially included in the manual, do not modify
// without updating the references in the *.tex files! // without updating the references in the *.tex files!
// Manual references: lines 31-51 (Error.tex) // Manual references: lines 29-49 (Error.tex)
#pragma once #pragma once
......
...@@ -18,7 +18,7 @@ ...@@ -18,7 +18,7 @@
// This file is partially included in the manual, do not modify // This file is partially included in the manual, do not modify
// without updating the references in the *.tex files! // without updating the references in the *.tex files!
// Manual references: lines 32-93 (Error.tex) // Manual references: lines 32-117 (Error.tex)
#pragma once #pragma once
......
...@@ -3,7 +3,7 @@ project(caf_cash CXX) ...@@ -3,7 +3,7 @@ project(caf_cash CXX)
# check whether submodules are available # check whether submodules are available
if(NOT EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/third_party/pybind/CMakeLists.txt") if(NOT EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/third_party/pybind/CMakeLists.txt")
message(WARNING "pybind submodule not loaded, skip libcaf_python") message(STATUS "Pybind submodule not loaded, skip libcaf_python.")
set(CAF_NO_PYTHON yes) set(CAF_NO_PYTHON yes)
else() else()
if(NOT "${CAF_PYTHON_CONFIG_BIN}" STREQUAL "") if(NOT "${CAF_PYTHON_CONFIG_BIN}" STREQUAL "")
......
#!/bin/sh
grep "define CAF_VERSION" libcaf_core/caf/config.hpp | awk '{printf "%d.%d.%d", int($3 / 10000), int($3 / 100) % 100, $3 % 100}' > version.txt
git rev-parse --abbrev-ref HEAD > branch.txt
git log --pretty=format:%h -n 1 > sha.txt
if test "$(cat branch.txt) = master" && git describe --tags --contains $(cat sha.txt) 1>tag.txt 2>/dev/null ; then
cp tag.txt release.txt
else
printf "%s" "$(cat version.txt)+exp.sha.$(cat sha.txt)" > release.txt
fi
#!/usr/bin/env python
import json
import sys
import re
from pandocfilters import toJSONFilter, Header, Str, RawBlock, RawInline, Image, Space
# This file fixes cross-references when building Sphinx documentation
# from the manual's .tex files.
# -- constants ----------------------------------------------------------------
singlefig_rx = re.compile(r"\\singlefig{(.+)}{(.+)}{(.+)}")
listing_rx = re.compile(r"\\(cppexample|iniexample|sourcefile)(?:\[(.+)\])?{(.+)}")
# -- factory functions --------------------------------------------------------
def make_rst_block(x):
return RawBlock('rst', x)
def make_rst_ref(x):
return RawInline('rst', ":ref:`" + x + "`")
def make_rst_image(img, caption, label):
return make_rst_block('.. figure:: ' + img + '.png\n' +
' :alt: ' + caption + '\n' +
' :name: ' + label + '\n' +
'\n' +
' ' + caption + '\n\n')
# -- code listing generation --------------------------------------------------
def parse_range(astr):
if not astr:
return set()
result = set()
for part in astr.split(','):
x = part.split('-')
result.update(range(int(x[0]), int(x[-1]) + 1))
return sorted(result)
def make_rst_listing(line_range, fname, language):
snippet = ''
if not line_range:
with open(fname, 'r') as fin:
for line in fin:
snippet += ' '
snippet += line
else:
with open(fname) as mfile:
for num, line in enumerate(mfile, 1):
if num in line_range:
snippet += ' '
snippet += line
return make_rst_block('.. code-block:: ' + language + '\n' +
'\n' +
snippet + '\n')
def cppexample(line_range, fname):
return make_rst_listing(line_range, '../../examples/{0}.cpp'.format(fname), 'C++')
def iniexample(line_range, fname):
return make_rst_listing(line_range, '../../examples/{0}.ini'.format(fname), 'ini')
def sourcefile(line_range, fname):
return make_rst_listing(line_range, '../../{0}'.format(fname), 'C++')
# -- Pandoc callback ----------------------------------------------------------
def behead(key, value, format, meta):
global singlefig_rx
# pandoc does not emit labels before sections -> insert
if key == 'Header':
raw_lbl = value[1][0]
if raw_lbl:
lbl = '.. _' + raw_lbl + ':\n\n'
value[1][0] = ''
return [make_rst_block(lbl), Header(value[0], value[1], value[2])]
# fix string parsing
elif key == 'Str':
if len(value) > 3:
# pandoc generates [refname] as strings for \ref{refname} -> fix
if value[0] == '[':
return make_rst_ref(value[1:-1])
elif value[1] == '[':
return make_rst_ref(value[2:-1])
# images don't have file endings in .tex -> add .png
elif key == 'Image':
return Image(value[0], value[1], [value[2][0] + ".png", value[2][1]])
elif key == 'RawBlock' and value[0] == 'latex':
# simply drop \clearpage
if value[1] == '\\clearpage':
return []
# convert \singlefig to Image node
m = singlefig_rx.match(value[1])
if m:
return make_rst_image(m.group(1), m.group(2), m.group(3))
m = listing_rx.match(value[1])
if m:
return globals()[m.group(1)](parse_range(m.group(2)), m.group(3))
sys.stderr.write("WARNING: unrecognized raw LaTeX" + str(value) + '\n')
if __name__ == "__main__":
toJSONFilter(behead)
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment