├── .cmake ├── Modules │ ├── Coveralls.cmake │ ├── CoverallsClear.cmake │ ├── CoverallsGenerateGcov.cmake │ ├── DebConfig.cmake │ ├── DebSourcePPA.cmake │ ├── FindCheck.cmake │ ├── PackageConfig.cmake │ ├── UploadPPA.cmake │ ├── copyright.expat │ └── uninstall.cmake ├── copy-source.sh └── git-archive-all.sh ├── .gitignore ├── .travis.yml ├── CMakeLists.txt ├── ChangeLog ├── HEADER ├── INSTALL.md ├── LICENSE ├── README.md ├── check ├── CMakeLists.txt └── test │ ├── array.c │ ├── misc.c │ ├── scalar.c │ ├── shared.c │ ├── test.c │ ├── test.h │ └── utils.h ├── debian.copyright ├── description.txt ├── doc └── csptr.3 ├── include └── csptr │ ├── array.h │ ├── common.h │ ├── smalloc.h │ └── smart_ptr.h └── src ├── array.c ├── config.h.in ├── mman.c └── mman.h /.cmake/Modules/Coveralls.cmake: -------------------------------------------------------------------------------- 1 | # 2 | # The MIT License (MIT) 3 | # 4 | # Permission is hereby granted, free of charge, to any person obtaining a copy 5 | # of this software and associated documentation files (the "Software"), to deal 6 | # in the Software without restriction, including without limitation the rights 7 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | # copies of the Software, and to permit persons to whom the Software is 9 | # furnished to do so, subject to the following conditions: 10 | # 11 | # The above copyright notice and this permission notice shall be included in all 12 | # copies or substantial portions of the Software. 13 | # 14 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | # SOFTWARE. 21 | # 22 | # Copyright (C) 2014 Joakim Söderberg 23 | # 24 | 25 | set(_CMAKE_SCRIPT_PATH ${CMAKE_CURRENT_LIST_DIR}) # must be outside coveralls_setup() to get correct path 26 | 27 | # 28 | # Param _COVERAGE_SRCS A list of source files that coverage should be collected for. 29 | # Param _COVERALLS_UPLOAD Upload the result to coveralls? 30 | # 31 | 32 | function(coveralls_setup _COVERAGE_SRCS _COVERALLS_UPLOAD) 33 | 34 | if (ARGC GREATER 2) 35 | set(_CMAKE_SCRIPT_PATH ${ARGN}) 36 | message(STATUS "Coveralls: Using alternate CMake script dir: ${_CMAKE_SCRIPT_PATH}") 37 | endif() 38 | 39 | if (NOT EXISTS "${_CMAKE_SCRIPT_PATH}/CoverallsClear.cmake") 40 | message(FATAL_ERROR "Coveralls: Missing ${_CMAKE_SCRIPT_PATH}/CoverallsClear.cmake") 41 | endif() 42 | 43 | if (NOT EXISTS "${_CMAKE_SCRIPT_PATH}/CoverallsGenerateGcov.cmake") 44 | message(FATAL_ERROR "Coveralls: Missing ${_CMAKE_SCRIPT_PATH}/CoverallsGenerateGcov.cmake") 45 | endif() 46 | 47 | # When passing a CMake list to an external process, the list 48 | # will be converted from the format "1;2;3" to "1 2 3". 49 | # This means the script we're calling won't see it as a list 50 | # of sources, but rather just one long path. We remedy this 51 | # by replacing ";" with "*" and then reversing that in the script 52 | # that we're calling. 53 | # http://cmake.3232098.n2.nabble.com/Passing-a-CMake-list-quot-as-is-quot-to-a-custom-target-td6505681.html 54 | set(COVERAGE_SRCS_TMP ${_COVERAGE_SRCS}) 55 | set(COVERAGE_SRCS "") 56 | foreach (COVERAGE_SRC ${COVERAGE_SRCS_TMP}) 57 | set(COVERAGE_SRCS "${COVERAGE_SRCS}*${COVERAGE_SRC}") 58 | endforeach() 59 | 60 | #message("Coverage sources: ${COVERAGE_SRCS}") 61 | set(COVERALLS_FILE ${PROJECT_BINARY_DIR}/coveralls.json) 62 | 63 | add_custom_target(coveralls_generate 64 | 65 | # Zero the coverage counters. 66 | COMMAND ${CMAKE_COMMAND} -DPROJECT_BINARY_DIR="${PROJECT_BINARY_DIR}" -P "${_CMAKE_SCRIPT_PATH}/CoverallsClear.cmake" 67 | 68 | # Run regress tests. 69 | COMMAND ${CMAKE_CTEST_COMMAND} --output-on-failure 70 | 71 | # Generate Gcov and translate it into coveralls JSON. 72 | # We do this by executing an external CMake script. 73 | # (We don't want this to run at CMake generation time, but after compilation and everything has run). 74 | COMMAND ${CMAKE_COMMAND} 75 | -DCOVERAGE_SRCS="${COVERAGE_SRCS}" # TODO: This is passed like: "a b c", not "a;b;c" 76 | -DCOVERALLS_OUTPUT_FILE="${COVERALLS_FILE}" 77 | -DCOV_PATH="${PROJECT_BINARY_DIR}" 78 | -DPROJECT_ROOT="${PROJECT_SOURCE_DIR}" 79 | -P "${_CMAKE_SCRIPT_PATH}/CoverallsGenerateGcov.cmake" 80 | 81 | WORKING_DIRECTORY ${PROJECT_BINARY_DIR} 82 | COMMENT "Generating coveralls output..." 83 | ) 84 | 85 | if (_COVERALLS_UPLOAD) 86 | message("COVERALLS UPLOAD: ON") 87 | 88 | find_program(CURL_EXECUTABLE curl) 89 | 90 | if (NOT CURL_EXECUTABLE) 91 | message(FATAL_ERROR "Coveralls: curl not found! Aborting") 92 | endif() 93 | 94 | add_custom_target(coveralls_upload 95 | # Upload the JSON to coveralls. 96 | COMMAND ${CURL_EXECUTABLE} 97 | -S -F json_file=@${COVERALLS_FILE} 98 | https://coveralls.io/api/v1/jobs 99 | 100 | DEPENDS coveralls_generate 101 | 102 | WORKING_DIRECTORY ${PROJECT_BINARY_DIR} 103 | COMMENT "Uploading coveralls output...") 104 | 105 | add_custom_target(coveralls DEPENDS coveralls_upload) 106 | else() 107 | message("COVERALLS UPLOAD: OFF") 108 | add_custom_target(coveralls DEPENDS coveralls_generate) 109 | endif() 110 | 111 | endfunction() 112 | 113 | macro(coveralls_turn_on_coverage) 114 | if(NOT (CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX) 115 | AND (NOT "${CMAKE_C_COMPILER_ID}" STREQUAL "Clang")) 116 | message(FATAL_ERROR "Coveralls: Compiler ${CMAKE_C_COMPILER_ID} is not GNU gcc! Aborting... You can set this on the command line using CC=/usr/bin/gcc CXX=/usr/bin/g++ cmake ..") 117 | endif() 118 | 119 | if(NOT CMAKE_BUILD_TYPE STREQUAL "Debug") 120 | message(FATAL_ERROR "Coveralls: Code coverage results with an optimised (non-Debug) build may be misleading! Add -DCMAKE_BUILD_TYPE=Debug") 121 | endif() 122 | 123 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -O0 -fprofile-arcs -ftest-coverage") 124 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g -O0 -fprofile-arcs -ftest-coverage") 125 | endmacro() 126 | 127 | 128 | 129 | -------------------------------------------------------------------------------- /.cmake/Modules/CoverallsClear.cmake: -------------------------------------------------------------------------------- 1 | # 2 | # The MIT License (MIT) 3 | # 4 | # Permission is hereby granted, free of charge, to any person obtaining a copy 5 | # of this software and associated documentation files (the "Software"), to deal 6 | # in the Software without restriction, including without limitation the rights 7 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | # copies of the Software, and to permit persons to whom the Software is 9 | # furnished to do so, subject to the following conditions: 10 | # 11 | # The above copyright notice and this permission notice shall be included in all 12 | # copies or substantial portions of the Software. 13 | # 14 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | # SOFTWARE. 21 | # 22 | # Copyright (C) 2014 Joakim Söderberg 23 | # 24 | 25 | # do not follow symlinks in file(GLOB_RECURSE ...) 26 | cmake_policy(SET CMP0009 NEW) 27 | 28 | file(GLOB_RECURSE GCDA_FILES "${PROJECT_BINARY_DIR}/*.gcda") 29 | if(NOT GCDA_FILES STREQUAL "") 30 | file(REMOVE ${GCDA_FILES}) 31 | endif() 32 | -------------------------------------------------------------------------------- /.cmake/Modules/CoverallsGenerateGcov.cmake: -------------------------------------------------------------------------------- 1 | # 2 | # The MIT License (MIT) 3 | # 4 | # Permission is hereby granted, free of charge, to any person obtaining a copy 5 | # of this software and associated documentation files (the "Software"), to deal 6 | # in the Software without restriction, including without limitation the rights 7 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | # copies of the Software, and to permit persons to whom the Software is 9 | # furnished to do so, subject to the following conditions: 10 | # 11 | # The above copyright notice and this permission notice shall be included in all 12 | # copies or substantial portions of the Software. 13 | # 14 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | # SOFTWARE. 21 | # 22 | # Copyright (C) 2014 Joakim Söderberg 23 | # 24 | # This is intended to be run by a custom target in a CMake project like this. 25 | # 0. Compile program with coverage support. 26 | # 1. Clear coverage data. (Recursively delete *.gcda in build dir) 27 | # 2. Run the unit tests. 28 | # 3. Run this script specifying which source files the coverage should be performed on. 29 | # 30 | # This script will then use gcov to generate .gcov files in the directory specified 31 | # via the COV_PATH var. This should probably be the same as your cmake build dir. 32 | # 33 | # It then parses the .gcov files to convert them into the Coveralls JSON format: 34 | # https://coveralls.io/docs/api 35 | # 36 | # Example for running as standalone CMake script from the command line: 37 | # (Note it is important the -P is at the end...) 38 | # $ cmake -DCOV_PATH=$(pwd) 39 | # -DCOVERAGE_SRCS="catcierge_rfid.c;catcierge_timer.c" 40 | # -P ../cmake/CoverallsGcovUpload.cmake 41 | # 42 | CMAKE_MINIMUM_REQUIRED(VERSION 2.8) 43 | 44 | 45 | # 46 | # Make sure we have the needed arguments. 47 | # 48 | if (NOT COVERALLS_OUTPUT_FILE) 49 | message(FATAL_ERROR "Coveralls: No coveralls output file specified. Please set COVERALLS_OUTPUT_FILE") 50 | endif() 51 | 52 | if (NOT COV_PATH) 53 | message(FATAL_ERROR "Coveralls: Missing coverage directory path where gcov files will be generated. Please set COV_PATH") 54 | endif() 55 | 56 | if (NOT COVERAGE_SRCS) 57 | message(FATAL_ERROR "Coveralls: Missing the list of source files that we should get the coverage data for COVERAGE_SRCS") 58 | endif() 59 | 60 | if (NOT PROJECT_ROOT) 61 | message(FATAL_ERROR "Coveralls: Missing PROJECT_ROOT.") 62 | endif() 63 | 64 | # Since it's not possible to pass a CMake list properly in the 65 | # "1;2;3" format to an external process, we have replaced the 66 | # ";" with "*", so reverse that here so we get it back into the 67 | # CMake list format. 68 | string(REGEX REPLACE "\\*" ";" COVERAGE_SRCS ${COVERAGE_SRCS}) 69 | 70 | # convert all paths in COVERAGE_SRCS to absolute paths 71 | set(COVERAGE_SRCS_TMP "") 72 | foreach (COVERAGE_SRC ${COVERAGE_SRCS}) 73 | if (NOT "${COVERAGE_SRC}" MATCHES "^/") 74 | set(COVERAGE_SRC ${PROJECT_ROOT}/${COVERAGE_SRC}) 75 | endif() 76 | list(APPEND COVERAGE_SRCS_TMP ${COVERAGE_SRC}) 77 | endforeach() 78 | set(COVERAGE_SRCS ${COVERAGE_SRCS_TMP}) 79 | unset(COVERAGE_SRCS_TMP) 80 | 81 | if (NOT DEFINED ENV{GCOV}) 82 | find_program(GCOV_EXECUTABLE gcov) 83 | else() 84 | find_program(GCOV_EXECUTABLE $ENV{GCOV}) 85 | endif() 86 | 87 | if (NOT GCOV_EXECUTABLE) 88 | message(FATAL_ERROR "gcov not found! Aborting...") 89 | endif() 90 | 91 | find_package(Git) 92 | 93 | set(JSON_REPO_TEMPLATE 94 | "{ 95 | \"head\": { 96 | \"id\": \"\@GIT_COMMIT_HASH\@\", 97 | \"author_name\": \"\@GIT_AUTHOR_NAME\@\", 98 | \"author_email\": \"\@GIT_AUTHOR_EMAIL\@\", 99 | \"committer_name\": \"\@GIT_COMMITTER_NAME\@\", 100 | \"committer_email\": \"\@GIT_COMMITTER_EMAIL\@\", 101 | \"message\": \"\@GIT_COMMIT_MESSAGE\@\" 102 | }, 103 | \"branch\": \"@GIT_BRANCH@\", 104 | \"remotes\": [] 105 | }" 106 | ) 107 | 108 | # TODO: Fill in git remote data 109 | if (GIT_FOUND) 110 | # Branch. 111 | execute_process( 112 | COMMAND ${GIT_EXECUTABLE} rev-parse --abbrev-ref HEAD 113 | WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} 114 | OUTPUT_VARIABLE GIT_BRANCH 115 | OUTPUT_STRIP_TRAILING_WHITESPACE 116 | ) 117 | 118 | macro (git_log_format FORMAT_CHARS VAR_NAME) 119 | execute_process( 120 | COMMAND ${GIT_EXECUTABLE} log -1 --pretty=format:%${FORMAT_CHARS} 121 | WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} 122 | OUTPUT_VARIABLE ${VAR_NAME} 123 | OUTPUT_STRIP_TRAILING_WHITESPACE 124 | ) 125 | endmacro() 126 | 127 | git_log_format(an GIT_AUTHOR_NAME) 128 | git_log_format(ae GIT_AUTHOR_EMAIL) 129 | git_log_format(cn GIT_COMMITTER_NAME) 130 | git_log_format(ce GIT_COMMITTER_EMAIL) 131 | git_log_format(B GIT_COMMIT_MESSAGE) 132 | git_log_format(H GIT_COMMIT_HASH) 133 | 134 | message("Git exe: ${GIT_EXECUTABLE}") 135 | message("Git branch: ${GIT_BRANCH}") 136 | message("Git author: ${GIT_AUTHOR_NAME}") 137 | message("Git e-mail: ${GIT_AUTHOR_EMAIL}") 138 | message("Git commiter name: ${GIT_COMMITTER_NAME}") 139 | message("Git commiter e-mail: ${GIT_COMMITTER_EMAIL}") 140 | message("Git commit hash: ${GIT_COMMIT_HASH}") 141 | message("Git commit message: ${GIT_COMMIT_MESSAGE}") 142 | 143 | string(CONFIGURE ${JSON_REPO_TEMPLATE} JSON_REPO_DATA) 144 | else() 145 | set(JSON_REPO_DATA "{}") 146 | endif() 147 | 148 | ############################# Macros ######################################### 149 | 150 | # 151 | # This macro converts from the full path format gcov outputs: 152 | # 153 | # /path/to/project/root/build/#path#to#project#root#subdir#the_file.c.gcov 154 | # 155 | # to the original source file path the .gcov is for: 156 | # 157 | # /path/to/project/root/subdir/the_file.c 158 | # 159 | macro(get_source_path_from_gcov_filename _SRC_FILENAME _GCOV_FILENAME) 160 | 161 | # /path/to/project/root/build/#path#to#project#root#subdir#the_file.c.gcov 162 | # -> 163 | # #path#to#project#root#subdir#the_file.c.gcov 164 | get_filename_component(_GCOV_FILENAME_WEXT ${_GCOV_FILENAME} NAME) 165 | 166 | # #path#to#project#root#subdir#the_file.c.gcov -> /path/to/project/root/subdir/the_file.c 167 | string(REGEX REPLACE "\\.gcov$" "" SRC_FILENAME_TMP ${_GCOV_FILENAME_WEXT}) 168 | string(REGEX REPLACE "\#" "/" SRC_FILENAME_TMP ${SRC_FILENAME_TMP}) 169 | set(${_SRC_FILENAME} "${SRC_FILENAME_TMP}") 170 | endmacro() 171 | 172 | ############################################################################## 173 | 174 | # Get the coverage data. 175 | file(GLOB_RECURSE GCDA_FILES "${COV_PATH}/*.gcda") 176 | message("GCDA files:") 177 | 178 | # Get a list of all the object directories needed by gcov 179 | # (The directories the .gcda files and .o files are found in) 180 | # and run gcov on those. 181 | foreach(GCDA ${GCDA_FILES}) 182 | message("Process: ${GCDA}") 183 | message("------------------------------------------------------------------------------") 184 | get_filename_component(GCDA_DIR ${GCDA} PATH) 185 | 186 | # 187 | # The -p below refers to "Preserve path components", 188 | # This means that the generated gcov filename of a source file will 189 | # keep the original files entire filepath, but / is replaced with #. 190 | # Example: 191 | # 192 | # /path/to/project/root/build/CMakeFiles/the_file.dir/subdir/the_file.c.gcda 193 | # ------------------------------------------------------------------------------ 194 | # File '/path/to/project/root/subdir/the_file.c' 195 | # Lines executed:68.34% of 199 196 | # /path/to/project/root/subdir/the_file.c:creating '#path#to#project#root#subdir#the_file.c.gcov' 197 | # 198 | # If -p is not specified then the file is named only "the_file.c.gcov" 199 | # 200 | execute_process( 201 | COMMAND ${GCOV_EXECUTABLE} -p -o ${GCDA_DIR} ${GCDA} 202 | WORKING_DIRECTORY ${COV_PATH} 203 | ) 204 | endforeach() 205 | 206 | # TODO: Make these be absolute path 207 | file(GLOB ALL_GCOV_FILES ${COV_PATH}/*.gcov) 208 | 209 | # Get only the filenames to use for filtering. 210 | #set(COVERAGE_SRCS_NAMES "") 211 | #foreach (COVSRC ${COVERAGE_SRCS}) 212 | # get_filename_component(COVSRC_NAME ${COVSRC} NAME) 213 | # message("${COVSRC} -> ${COVSRC_NAME}") 214 | # list(APPEND COVERAGE_SRCS_NAMES "${COVSRC_NAME}") 215 | #endforeach() 216 | 217 | # 218 | # Filter out all but the gcov files we want. 219 | # 220 | # We do this by comparing the list of COVERAGE_SRCS filepaths that the 221 | # user wants the coverage data for with the paths of the generated .gcov files, 222 | # so that we only keep the relevant gcov files. 223 | # 224 | # Example: 225 | # COVERAGE_SRCS = 226 | # /path/to/project/root/subdir/the_file.c 227 | # 228 | # ALL_GCOV_FILES = 229 | # /path/to/project/root/build/#path#to#project#root#subdir#the_file.c.gcov 230 | # /path/to/project/root/build/#path#to#project#root#subdir#other_file.c.gcov 231 | # 232 | # Result should be: 233 | # GCOV_FILES = 234 | # /path/to/project/root/build/#path#to#project#root#subdir#the_file.c.gcov 235 | # 236 | set(GCOV_FILES "") 237 | #message("Look in coverage sources: ${COVERAGE_SRCS}") 238 | message("\nFilter out unwanted GCOV files:") 239 | message("===============================") 240 | 241 | set(COVERAGE_SRCS_REMAINING ${COVERAGE_SRCS}) 242 | 243 | foreach (GCOV_FILE ${ALL_GCOV_FILES}) 244 | 245 | # 246 | # /path/to/project/root/build/#path#to#project#root#subdir#the_file.c.gcov 247 | # -> 248 | # /path/to/project/root/subdir/the_file.c 249 | get_source_path_from_gcov_filename(GCOV_SRC_PATH ${GCOV_FILE}) 250 | file(RELATIVE_PATH GCOV_SRC_REL_PATH "${PROJECT_ROOT}" "${GCOV_SRC_PATH}") 251 | 252 | # Is this in the list of source files? 253 | # TODO: We want to match against relative path filenames from the source file root... 254 | list(FIND COVERAGE_SRCS ${GCOV_SRC_PATH} WAS_FOUND) 255 | 256 | if (NOT WAS_FOUND EQUAL -1) 257 | message("YES: ${GCOV_FILE}") 258 | list(APPEND GCOV_FILES ${GCOV_FILE}) 259 | 260 | # We remove it from the list, so we don't bother searching for it again. 261 | # Also files left in COVERAGE_SRCS_REMAINING after this loop ends should 262 | # have coverage data generated from them (no lines are covered). 263 | list(REMOVE_ITEM COVERAGE_SRCS_REMAINING ${GCOV_SRC_PATH}) 264 | else() 265 | message("NO: ${GCOV_FILE}") 266 | endif() 267 | endforeach() 268 | 269 | # TODO: Enable setting these 270 | set(JSON_SERVICE_NAME "travis-ci") 271 | set(JSON_SERVICE_JOB_ID $ENV{TRAVIS_JOB_ID}) 272 | set(JSON_REPO_TOKEN $ENV{COVERALLS_REPO_TOKEN}) 273 | 274 | set(JSON_TEMPLATE 275 | "{ 276 | \"repo_token\": \"\@JSON_REPO_TOKEN\@\", 277 | \"service_name\": \"\@JSON_SERVICE_NAME\@\", 278 | \"service_job_id\": \"\@JSON_SERVICE_JOB_ID\@\", 279 | \"source_files\": \@JSON_GCOV_FILES\@, 280 | \"git\": \@JSON_REPO_DATA\@ 281 | }" 282 | ) 283 | 284 | set(SRC_FILE_TEMPLATE 285 | "{ 286 | \"name\": \"\@GCOV_SRC_REL_PATH\@\", 287 | \"source_digest\": \"\@GCOV_CONTENTS_MD5\@\", 288 | \"coverage\": \@GCOV_FILE_COVERAGE\@ 289 | }" 290 | ) 291 | 292 | message("\nGenerate JSON for files:") 293 | message("=========================") 294 | 295 | set(JSON_GCOV_FILES "[") 296 | 297 | # Read the GCOV files line by line and get the coverage data. 298 | foreach (GCOV_FILE ${GCOV_FILES}) 299 | 300 | get_source_path_from_gcov_filename(GCOV_SRC_PATH ${GCOV_FILE}) 301 | file(RELATIVE_PATH GCOV_SRC_REL_PATH "${PROJECT_ROOT}" "${GCOV_SRC_PATH}") 302 | 303 | # The new coveralls API doesn't need the entire source (Yay!) 304 | # However, still keeping that part for now. Will cleanup in the future. 305 | file(MD5 "${GCOV_SRC_PATH}" GCOV_CONTENTS_MD5) 306 | message("MD5: ${GCOV_SRC_PATH} = ${GCOV_CONTENTS_MD5}") 307 | 308 | # Loads the gcov file as a list of lines. 309 | # (We first open the file and replace all occurences of [] with _ 310 | # because CMake will fail to parse a line containing unmatched brackets... 311 | # also the \ to escaped \n in macros screws up things.) 312 | # https://public.kitware.com/Bug/view.php?id=15369 313 | file(READ ${GCOV_FILE} GCOV_CONTENTS) 314 | string(REPLACE "[" "_" GCOV_CONTENTS "${GCOV_CONTENTS}") 315 | string(REPLACE "]" "_" GCOV_CONTENTS "${GCOV_CONTENTS}") 316 | string(REPLACE "\\" "_" GCOV_CONTENTS "${GCOV_CONTENTS}") 317 | 318 | # Remove file contents to avoid encoding issues (cmake 2.8 has no ENCODING option) 319 | string(REGEX REPLACE "([^:]*):([^:]*):([^\n]*)\n" "\\1:\\2: \n" GCOV_CONTENTS "${GCOV_CONTENTS}") 320 | file(WRITE ${GCOV_FILE}_tmp "${GCOV_CONTENTS}") 321 | 322 | file(STRINGS ${GCOV_FILE}_tmp GCOV_LINES) 323 | list(LENGTH GCOV_LINES LINE_COUNT) 324 | 325 | # Instead of trying to parse the source from the 326 | # gcov file, simply read the file contents from the source file. 327 | # (Parsing it from the gcov is hard because C-code uses ; in many places 328 | # which also happens to be the same as the CMake list delimeter). 329 | file(READ ${GCOV_SRC_PATH} GCOV_FILE_SOURCE) 330 | 331 | string(REPLACE "\\" "\\\\" GCOV_FILE_SOURCE "${GCOV_FILE_SOURCE}") 332 | string(REGEX REPLACE "\"" "\\\\\"" GCOV_FILE_SOURCE "${GCOV_FILE_SOURCE}") 333 | string(REPLACE "\t" "\\\\t" GCOV_FILE_SOURCE "${GCOV_FILE_SOURCE}") 334 | string(REPLACE "\r" "\\\\r" GCOV_FILE_SOURCE "${GCOV_FILE_SOURCE}") 335 | string(REPLACE "\n" "\\\\n" GCOV_FILE_SOURCE "${GCOV_FILE_SOURCE}") 336 | # According to http://json.org/ these should be escaped as well. 337 | # Don't know how to do that in CMake however... 338 | #string(REPLACE "\b" "\\\\b" GCOV_FILE_SOURCE "${GCOV_FILE_SOURCE}") 339 | #string(REPLACE "\f" "\\\\f" GCOV_FILE_SOURCE "${GCOV_FILE_SOURCE}") 340 | #string(REGEX REPLACE "\u([a-fA-F0-9]{4})" "\\\\u\\1" GCOV_FILE_SOURCE "${GCOV_FILE_SOURCE}") 341 | 342 | # We want a json array of coverage data as a single string 343 | # start building them from the contents of the .gcov 344 | set(GCOV_FILE_COVERAGE "[") 345 | 346 | set(GCOV_LINE_COUNT 1) # Line number for the .gcov. 347 | set(DO_SKIP 0) 348 | foreach (GCOV_LINE ${GCOV_LINES}) 349 | #message("${GCOV_LINE}") 350 | # Example of what we're parsing: 351 | # Hitcount |Line | Source 352 | # " 8: 26: if (!allowed || (strlen(allowed) == 0))" 353 | string(REGEX REPLACE 354 | "^([^:]*):([^:]*):(.*)$" 355 | "\\1;\\2;\\3" 356 | RES 357 | "${GCOV_LINE}") 358 | 359 | # Check if we should exclude lines using the Lcov syntax. 360 | string(REGEX MATCH "LCOV_EXCL_START" START_SKIP "${GCOV_LINE}") 361 | string(REGEX MATCH "LCOV_EXCL_END" END_SKIP "${GCOV_LINE}") 362 | string(REGEX MATCH "LCOV_EXCL_LINE" LINE_SKIP "${GCOV_LINE}") 363 | 364 | set(RESET_SKIP 0) 365 | if (LINE_SKIP AND NOT DO_SKIP) 366 | set(DO_SKIP 1) 367 | set(RESET_SKIP 1) 368 | endif() 369 | 370 | if (START_SKIP) 371 | set(DO_SKIP 1) 372 | message("${GCOV_LINE_COUNT}: Start skip") 373 | endif() 374 | 375 | if (END_SKIP) 376 | set(DO_SKIP 0) 377 | endif() 378 | 379 | list(LENGTH RES RES_COUNT) 380 | 381 | if (RES_COUNT GREATER 2) 382 | list(GET RES 0 HITCOUNT) 383 | list(GET RES 1 LINE) 384 | list(GET RES 2 SOURCE) 385 | 386 | string(STRIP ${HITCOUNT} HITCOUNT) 387 | string(STRIP ${LINE} LINE) 388 | 389 | # Lines with 0 line numbers are metadata and can be ignored. 390 | if (NOT ${LINE} EQUAL 0) 391 | 392 | if (DO_SKIP) 393 | set(GCOV_FILE_COVERAGE "${GCOV_FILE_COVERAGE}null, ") 394 | else() 395 | # Translate the hitcount into valid JSON values. 396 | if (${HITCOUNT} STREQUAL "#####" OR ${HITCOUNT} STREQUAL "=====") 397 | set(GCOV_FILE_COVERAGE "${GCOV_FILE_COVERAGE}0, ") 398 | elseif (${HITCOUNT} STREQUAL "-") 399 | set(GCOV_FILE_COVERAGE "${GCOV_FILE_COVERAGE}null, ") 400 | else() 401 | set(GCOV_FILE_COVERAGE "${GCOV_FILE_COVERAGE}${HITCOUNT}, ") 402 | endif() 403 | endif() 404 | endif() 405 | else() 406 | message(WARNING "Failed to properly parse line (RES_COUNT = ${RES_COUNT}) ${GCOV_FILE}:${GCOV_LINE_COUNT}\n-->${GCOV_LINE}") 407 | endif() 408 | 409 | if (RESET_SKIP) 410 | set(DO_SKIP 0) 411 | endif() 412 | math(EXPR GCOV_LINE_COUNT "${GCOV_LINE_COUNT}+1") 413 | endforeach() 414 | 415 | message("${GCOV_LINE_COUNT} of ${LINE_COUNT} lines read!") 416 | 417 | # Advanced way of removing the trailing comma in the JSON array. 418 | # "[1, 2, 3, " -> "[1, 2, 3" 419 | string(REGEX REPLACE ",[ ]*$" "" GCOV_FILE_COVERAGE ${GCOV_FILE_COVERAGE}) 420 | 421 | # Append the trailing ] to complete the JSON array. 422 | set(GCOV_FILE_COVERAGE "${GCOV_FILE_COVERAGE}]") 423 | 424 | # Generate the final JSON for this file. 425 | message("Generate JSON for file: ${GCOV_SRC_REL_PATH}...") 426 | string(CONFIGURE ${SRC_FILE_TEMPLATE} FILE_JSON) 427 | 428 | set(JSON_GCOV_FILES "${JSON_GCOV_FILES}${FILE_JSON}, ") 429 | endforeach() 430 | 431 | # Loop through all files we couldn't find any coverage for 432 | # as well, and generate JSON for those as well with 0% coverage. 433 | foreach(NOT_COVERED_SRC ${COVERAGE_SRCS_REMAINING}) 434 | 435 | # Set variables for json replacement 436 | set(GCOV_SRC_PATH ${NOT_COVERED_SRC}) 437 | file(MD5 "${GCOV_SRC_PATH}" GCOV_CONTENTS_MD5) 438 | file(RELATIVE_PATH GCOV_SRC_REL_PATH "${PROJECT_ROOT}" "${GCOV_SRC_PATH}") 439 | 440 | # Loads the source file as a list of lines. 441 | file(STRINGS ${NOT_COVERED_SRC} SRC_LINES) 442 | 443 | set(GCOV_FILE_COVERAGE "[") 444 | set(GCOV_FILE_SOURCE "") 445 | 446 | foreach (SOURCE ${SRC_LINES}) 447 | set(GCOV_FILE_COVERAGE "${GCOV_FILE_COVERAGE}null, ") 448 | 449 | string(REPLACE "\\" "\\\\" SOURCE "${SOURCE}") 450 | string(REGEX REPLACE "\"" "\\\\\"" SOURCE "${SOURCE}") 451 | string(REPLACE "\t" "\\\\t" SOURCE "${SOURCE}") 452 | string(REPLACE "\r" "\\\\r" SOURCE "${SOURCE}") 453 | set(GCOV_FILE_SOURCE "${GCOV_FILE_SOURCE}${SOURCE}\\n") 454 | endforeach() 455 | 456 | # Remove trailing comma, and complete JSON array with ] 457 | string(REGEX REPLACE ",[ ]*$" "" GCOV_FILE_COVERAGE ${GCOV_FILE_COVERAGE}) 458 | set(GCOV_FILE_COVERAGE "${GCOV_FILE_COVERAGE}]") 459 | 460 | # Generate the final JSON for this file. 461 | message("Generate JSON for non-gcov file: ${NOT_COVERED_SRC}...") 462 | string(CONFIGURE ${SRC_FILE_TEMPLATE} FILE_JSON) 463 | set(JSON_GCOV_FILES "${JSON_GCOV_FILES}${FILE_JSON}, ") 464 | endforeach() 465 | 466 | # Get rid of trailing comma. 467 | string(REGEX REPLACE ",[ ]*$" "" JSON_GCOV_FILES ${JSON_GCOV_FILES}) 468 | set(JSON_GCOV_FILES "${JSON_GCOV_FILES}]") 469 | 470 | # Generate the final complete JSON! 471 | message("Generate final JSON...") 472 | string(CONFIGURE ${JSON_TEMPLATE} JSON) 473 | 474 | file(WRITE "${COVERALLS_OUTPUT_FILE}" "${JSON}") 475 | message("###########################################################################") 476 | message("Generated coveralls JSON containing coverage data:") 477 | message("${COVERALLS_OUTPUT_FILE}") 478 | message("###########################################################################") 479 | 480 | -------------------------------------------------------------------------------- /.cmake/Modules/DebConfig.cmake: -------------------------------------------------------------------------------- 1 | # build a Debian package for Launchpad 2 | set(CPACK_DEBIAN_PACKAGE_NAME "libcsptr-dev") 3 | set(CPACK_DEBIAN_PACKAGE_PRIORITY "optional") 4 | set(CPACK_DEBIAN_PACKAGE_SECTION "devel") 5 | set(CPACK_DEBIAN_PACKAGE_HOMEPAGE "https://github.com/Snaipe/libcsptr") 6 | set(CPACK_DEBIAN_BUILD_DEPENDS debhelper cmake) 7 | set(CPACK_PACKAGE_DESCRIPTION_FILE "${CMAKE_SOURCE_DIR}/description.txt") 8 | 9 | set(CPACK_DEBIAN_PACKAGE_SOURCE_COPY "${CMAKE_SOURCE_DIR}/.cmake/copy-source.sh") 10 | 11 | set(CPACK_DEBIAN_DISTRIBUTION_NAME ubuntu) 12 | set(CPACK_DEBIAN_DISTRIBUTION_RELEASES precise trusty vivid wily xenial) 13 | 14 | set(DPUT_HOST "snaipewastaken-ppa") 15 | set(DPUT_SNAPSHOT_HOST "snaipewastaken-ppa") 16 | set(CPACK_DEBIAN_PACKAGE_DOCS "/usr/share/man/*") 17 | set(CPACK_DEBIAN_PACKAGE_INSTALL "/usr/include" "/usr/lib/*.a") 18 | 19 | include (DebSourcePPA) 20 | -------------------------------------------------------------------------------- /.cmake/Modules/DebSourcePPA.cmake: -------------------------------------------------------------------------------- 1 | ## Debian Source Package Generator 2 | # 3 | # Copyright (c) 2010 Daniel Pfeifer 4 | # Many modifications by Rosen Diankov 5 | # 6 | # Creates source debian files and manages library dependencies 7 | # 8 | # Features: 9 | # 10 | # - Automatically generates symbols and run-time dependencies from the build dependencies 11 | # - Custom copy of source directory via CPACK_DEBIAN_PACKAGE_SOURCE_COPY 12 | # - Simultaneous output of multiple debian source packages for each distribution 13 | # - Can specificy distribution-specific dependencies by suffixing DEPENDS with _${DISTRO_NAME}, for example: CPACK_DEBIAN_PACKAGE_DEPENDS_LUCID, CPACK_COMPONENT_MYCOMP0_DEPENDS_LUCID 14 | # 15 | # Usage: 16 | # 17 | # set(CPACK_DEBIAN_BUILD_DEPENDS debhelper cmake) 18 | # set(CPACK_DEBIAN_PACKAGE_PRIORITY optional) 19 | # set(CPACK_DEBIAN_PACKAGE_SECTION devel) 20 | # set(CPACK_DEBIAN_CMAKE_OPTIONS "-DMYOPTION=myvalue") 21 | # set(CPACK_DEBIAN_PACKAGE_DEPENDS mycomp0 mycomp1 some_ubuntu_package) 22 | # set(CPACK_DEBIAN_PACKAGE_DEPENDS_UBUNTU_LUCID mycomp0 mycomp1 lucid_specific_package) 23 | # set(CPACK_DEBIAN_PACKAGE_NAME mypackage) 24 | # set(CPACK_DEBIAN_PACKAGE_REMOVE_SOURCE_FILES unnecessary_file unnecessary_dir/file0) 25 | # set(CPACK_DEBIAN_PACKAGE_SOURCE_COPY svn export --force) # if using subversion 26 | # set(CPACK_DEBIAN_DISTRIBUTION_NAME ubuntu) 27 | # set(CPACK_DEBIAN_DISTRIBUTION_RELEASES karmic lucid maverick natty) 28 | # set(CPACK_DEBIAN_CHANGELOG " * Extra change log lines") 29 | # set(CPACK_DEBIAN_PACKAGE_SUGGESTS "ipython") 30 | # set(CPACK_COMPONENT_X_RECOMMENDS "recommended-package") 31 | ## 32 | 33 | find_program(DEBUILD_EXECUTABLE debuild) 34 | find_program(DPUT_EXECUTABLE dput) 35 | 36 | if(NOT DEBUILD_EXECUTABLE OR NOT DPUT_EXECUTABLE) 37 | return() 38 | endif(NOT DEBUILD_EXECUTABLE OR NOT DPUT_EXECUTABLE) 39 | 40 | # DEBIAN/control 41 | # debian policy enforce lower case for package name 42 | # Package: (mandatory) 43 | IF(NOT CPACK_DEBIAN_PACKAGE_NAME) 44 | STRING(TOLOWER "${CPACK_PACKAGE_NAME}" CPACK_DEBIAN_PACKAGE_NAME) 45 | ENDIF(NOT CPACK_DEBIAN_PACKAGE_NAME) 46 | 47 | # Section: (recommended) 48 | IF(NOT CPACK_DEBIAN_PACKAGE_SECTION) 49 | SET(CPACK_DEBIAN_PACKAGE_SECTION "devel") 50 | ENDIF(NOT CPACK_DEBIAN_PACKAGE_SECTION) 51 | 52 | # Priority: (recommended) 53 | IF(NOT CPACK_DEBIAN_PACKAGE_PRIORITY) 54 | SET(CPACK_DEBIAN_PACKAGE_PRIORITY "optional") 55 | ENDIF(NOT CPACK_DEBIAN_PACKAGE_PRIORITY) 56 | 57 | file(STRINGS ${CPACK_PACKAGE_DESCRIPTION_FILE} DESC_LINES) 58 | foreach(LINE ${DESC_LINES}) 59 | set(DEB_LONG_DESCRIPTION "${DEB_LONG_DESCRIPTION} ${LINE}\n") 60 | endforeach(LINE ${DESC_LINES}) 61 | 62 | file(REMOVE_RECURSE "${CMAKE_BINARY_DIR}/Debian") 63 | file(MAKE_DIRECTORY "${CMAKE_BINARY_DIR}/Debian") 64 | set(DEBIAN_SOURCE_ORIG_DIR "${CMAKE_BINARY_DIR}/Debian/${CPACK_DEBIAN_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}") 65 | 66 | if( CPACK_DEBIAN_PACKAGE_SOURCE_COPY ) 67 | execute_process(COMMAND ${CPACK_DEBIAN_PACKAGE_SOURCE_COPY} "${CMAKE_SOURCE_DIR}" "${DEBIAN_SOURCE_ORIG_DIR}.orig") 68 | else() 69 | execute_process(COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR} "${DEBIAN_SOURCE_ORIG_DIR}.orig") 70 | execute_process(COMMAND ${CMAKE_COMMAND} -E remove_directory "${DEBIAN_SOURCE_ORIG_DIR}.orig/.git") 71 | execute_process(COMMAND ${CMAKE_COMMAND} -E remove_directory "${DEBIAN_SOURCE_ORIG_DIR}.orig/.svn") 72 | endif() 73 | 74 | # remove unnecessary folders 75 | foreach(REMOVE_DIR ${CPACK_DEBIAN_PACKAGE_REMOVE_SOURCE_FILES}) 76 | file(REMOVE_RECURSE ${DEBIAN_SOURCE_ORIG_DIR}.orig/${REMOVE_DIR}) 77 | endforeach() 78 | 79 | # create the original source tar 80 | execute_process(COMMAND ${CMAKE_COMMAND} -E tar czf "${CPACK_DEBIAN_PACKAGE_NAME}_${CPACK_PACKAGE_VERSION}.orig.tar.gz" "${CPACK_DEBIAN_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}.orig" WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/Debian) 81 | 82 | set(DEB_SOURCE_CHANGES) 83 | foreach(RELEASE ${CPACK_DEBIAN_DISTRIBUTION_RELEASES}) 84 | set(DEBIAN_SOURCE_DIR "${DEBIAN_SOURCE_ORIG_DIR}-${CPACK_DEBIAN_DISTRIBUTION_NAME}1~${RELEASE}1") 85 | set(RELEASE_PACKAGE_VERSION "${CPACK_PACKAGE_VERSION}-${CPACK_DEBIAN_DISTRIBUTION_NAME}1~${RELEASE}1") 86 | string(TOUPPER ${RELEASE} RELEASE_UPPER) 87 | string(TOUPPER ${CPACK_DEBIAN_DISTRIBUTION_NAME} DISTRIBUTION_NAME_UPPER) 88 | file(MAKE_DIRECTORY ${DEBIAN_SOURCE_DIR}/debian) 89 | ############################################################################## 90 | # debian/control 91 | set(DEBIAN_CONTROL ${DEBIAN_SOURCE_DIR}/debian/control) 92 | file(WRITE ${DEBIAN_CONTROL} 93 | "Source: ${CPACK_DEBIAN_PACKAGE_NAME}\n" 94 | "Section: ${CPACK_DEBIAN_PACKAGE_SECTION}\n" 95 | "Priority: ${CPACK_DEBIAN_PACKAGE_PRIORITY}\n" 96 | "DM-Upload-Allowed: yes\n" 97 | "Maintainer: ${CPACK_PACKAGE_CONTACT}\n" 98 | "Build-Depends: " 99 | ) 100 | 101 | if( CPACK_DEBIAN_BUILD_DEPENDS_${DISTRIBUTION_NAME_UPPER}_${RELEASE_UPPER} ) 102 | foreach(DEP ${CPACK_DEBIAN_BUILD_DEPENDS_${DISTRIBUTION_NAME_UPPER}_${RELEASE_UPPER}}) 103 | file(APPEND ${DEBIAN_CONTROL} "${DEP}, ") 104 | endforeach(DEP ${CPACK_DEBIAN_BUILD_DEPENDS_${DISTRIBUTION_NAME_UPPER}_${RELEASE_UPPER}}) 105 | else( CPACK_DEBIAN_BUILD_DEPENDS_${DISTRIBUTION_NAME_UPPER}_${RELEASE_UPPER} ) 106 | if( CPACK_DEBIAN_BUILD_DEPENDS_${DISTRIBUTION_NAME_UPPER} ) 107 | foreach(DEP ${CPACK_DEBIAN_BUILD_DEPENDS_${DISTRIBUTION_NAME_UPPER}}) 108 | file(APPEND ${DEBIAN_CONTROL} "${DEP}, ") 109 | endforeach(DEP ${CPACK_DEBIAN_BUILD_DEPENDS_${DISTRIBUTION_NAME_UPPER}}) 110 | else( CPACK_DEBIAN_BUILD_DEPENDS_${DISTRIBUTION_NAME_UPPER} ) 111 | foreach(DEP ${CPACK_DEBIAN_BUILD_DEPENDS}) 112 | file(APPEND ${DEBIAN_CONTROL} "${DEP}, ") 113 | endforeach(DEP ${CPACK_DEBIAN_BUILD_DEPENDS}) 114 | endif( CPACK_DEBIAN_BUILD_DEPENDS_${DISTRIBUTION_NAME_UPPER} ) 115 | endif( CPACK_DEBIAN_BUILD_DEPENDS_${DISTRIBUTION_NAME_UPPER}_${RELEASE_UPPER} ) 116 | 117 | 118 | file(APPEND ${DEBIAN_CONTROL} "\n" 119 | "Standards-Version: 3.8.4\n" 120 | "Homepage: ${CPACK_PACKAGE_VENDOR}\n" 121 | "\n" 122 | "Package: ${CPACK_DEBIAN_PACKAGE_NAME}\n" 123 | "Architecture: any\n" 124 | "Depends: " 125 | ) 126 | 127 | if( CPACK_DEBIAN_PACKAGE_DEPENDS_${DISTRIBUTION_NAME_UPPER}_${RELEASE_UPPER} ) 128 | foreach(DEP ${CPACK_DEBIAN_PACKAGE_DEPENDS_${DISTRIBUTION_NAME_UPPER}_${RELEASE_UPPER}}) 129 | file(APPEND ${DEBIAN_CONTROL} "${DEP}, ") 130 | endforeach(DEP ${CPACK_DEBIAN_PACKAGE_DEPENDS_${DISTRIBUTION_NAME_UPPER}_${RELEASE_UPPER}}) 131 | else( CPACK_DEBIAN_PACKAGE_DEPENDS_${DISTRIBUTION_NAME_UPPER}_${RELEASE_UPPER} ) 132 | if( CPACK_DEBIAN_PACKAGE_DEPENDS_${DISTRIBUTION_NAME_UPPER} ) 133 | foreach(DEP ${CPACK_DEBIAN_PACKAGE_DEPENDS_${DISTRIBUTION_NAME_UPPER}}) 134 | file(APPEND ${DEBIAN_CONTROL} "${DEP}, ") 135 | endforeach(DEP ${CPACK_DEBIAN_PACKAGE_DEPENDS_${DISTRIBUTION_NAME_UPPER}}) 136 | else( CPACK_DEBIAN_PACKAGE_DEPENDS_${DISTRIBUTION_NAME_UPPER} ) 137 | foreach(DEP ${CPACK_DEBIAN_PACKAGE_DEPENDS}) 138 | file(APPEND ${DEBIAN_CONTROL} "${DEP}, ") 139 | endforeach(DEP ${CPACK_DEBIAN_PACKAGE_DEPENDS}) 140 | endif( CPACK_DEBIAN_PACKAGE_DEPENDS_${DISTRIBUTION_NAME_UPPER} ) 141 | endif( CPACK_DEBIAN_PACKAGE_DEPENDS_${DISTRIBUTION_NAME_UPPER}_${RELEASE_UPPER} ) 142 | 143 | file(APPEND ${DEBIAN_CONTROL} "\nRecommends: ") 144 | if( CPACK_DEBIAN_PACKAGE_RECOMMENDS_${DISTRIBUTION_NAME_UPPER}_${RELEASE_UPPER} ) 145 | foreach(DEP ${CPACK_DEBIAN_PACKAGE_RECOMMENDS_${DISTRIBUTION_NAME_UPPER}_${RELEASE_UPPER}}) 146 | file(APPEND ${DEBIAN_CONTROL} "${DEP}, ") 147 | endforeach(DEP ${CPACK_DEBIAN_PACKAGE_RECOMMENDS_${DISTRIBUTION_NAME_UPPER}_${RELEASE_UPPER}}) 148 | else( CPACK_DEBIAN_PACKAGE_RECOMMENDS_${DISTRIBUTION_NAME_UPPER}_${RELEASE_UPPER} ) 149 | if( CPACK_DEBIAN_PACKAGE_RECOMMENDS_${DISTRIBUTION_NAME_UPPER} ) 150 | foreach(DEP ${CPACK_DEBIAN_PACKAGE_RECOMMENDS_${DISTRIBUTION_NAME_UPPER}}) 151 | file(APPEND ${DEBIAN_CONTROL} "${DEP}, ") 152 | endforeach(DEP ${CPACK_DEBIAN_PACKAGE_RECOMMENDS_${DISTRIBUTION_NAME_UPPER}}) 153 | else( CPACK_DEBIAN_PACKAGE_RECOMMENDS_${DISTRIBUTION_NAME_UPPER} ) 154 | foreach(DEP ${CPACK_DEBIAN_PACKAGE_RECOMMENDS}) 155 | file(APPEND ${DEBIAN_CONTROL} "${DEP}, ") 156 | endforeach(DEP ${CPACK_DEBIAN_PACKAGE_RECOMMENDS}) 157 | endif( CPACK_DEBIAN_PACKAGE_RECOMMENDS_${DISTRIBUTION_NAME_UPPER} ) 158 | endif( CPACK_DEBIAN_PACKAGE_RECOMMENDS_${DISTRIBUTION_NAME_UPPER}_${RELEASE_UPPER} ) 159 | 160 | file(APPEND ${DEBIAN_CONTROL} "\nSuggests: ") 161 | if( CPACK_DEBIAN_PACKAGE_SUGGESTS_${DISTRIBUTION_NAME_UPPER}_${RELEASE_UPPER} ) 162 | foreach(DEP ${CPACK_DEBIAN_PACKAGE_SUGGESTS_${DISTRIBUTION_NAME_UPPER}_${RELEASE_UPPER}}) 163 | file(APPEND ${DEBIAN_CONTROL} "${DEP}, ") 164 | endforeach(DEP ${CPACK_DEBIAN_PACKAGE_SUGGESTS_${DISTRIBUTION_NAME_UPPER}_${RELEASE_UPPER}}) 165 | else( CPACK_DEBIAN_PACKAGE_SUGGESTS_${DISTRIBUTION_NAME_UPPER}_${RELEASE_UPPER} ) 166 | if( CPACK_DEBIAN_PACKAGE_SUGGESTS_${DISTRIBUTION_NAME_UPPER} ) 167 | foreach(DEP ${CPACK_DEBIAN_PACKAGE_SUGGESTS_${DISTRIBUTION_NAME_UPPER}}) 168 | file(APPEND ${DEBIAN_CONTROL} "${DEP}, ") 169 | endforeach(DEP ${CPACK_DEBIAN_PACKAGE_SUGGESTS_${DISTRIBUTION_NAME_UPPER}}) 170 | else( CPACK_DEBIAN_PACKAGE_SUGGESTS_${DISTRIBUTION_NAME_UPPER} ) 171 | foreach(DEP ${CPACK_DEBIAN_PACKAGE_SUGGESTS}) 172 | file(APPEND ${DEBIAN_CONTROL} "${DEP}, ") 173 | endforeach(DEP ${CPACK_DEBIAN_PACKAGE_SUGGESTS}) 174 | endif( CPACK_DEBIAN_PACKAGE_SUGGESTS_${DISTRIBUTION_NAME_UPPER} ) 175 | endif( CPACK_DEBIAN_PACKAGE_SUGGESTS_${DISTRIBUTION_NAME_UPPER}_${RELEASE_UPPER} ) 176 | 177 | file(APPEND ${DEBIAN_CONTROL} "\n" 178 | "Description: ${CPACK_PACKAGE_DISPLAY_NAME} ${CPACK_PACKAGE_DESCRIPTION_SUMMARY}\n" 179 | "${DEB_LONG_DESCRIPTION}" 180 | ) 181 | 182 | foreach(COMPONENT ${CPACK_COMPONENTS_ALL}) 183 | string(TOUPPER ${COMPONENT} UPPER_COMPONENT) 184 | set(DEPENDS "\${shlibs:Depends}") 185 | if( CPACK_COMPONENT_${UPPER_COMPONENT}_DEPENDS_${DISTRIBUTION_NAME_UPPER}_${RELEASE_UPPER} ) 186 | foreach(DEP ${CPACK_COMPONENT_${UPPER_COMPONENT}_DEPENDS_${DISTRIBUTION_NAME_UPPER}_${RELEASE_UPPER}}) 187 | set(DEPENDS "${DEPENDS}, ${DEP}") 188 | endforeach(DEP ${CPACK_COMPONENT_${UPPER_COMPONENT}_DEPENDS_${DISTRIBUTION_NAME_UPPER}_${RELEASE_UPPER}}) 189 | else( CPACK_COMPONENT_${UPPER_COMPONENT}_DEPENDS_${DISTRIBUTION_NAME_UPPER}_${RELEASE_UPPER} ) 190 | if( CPACK_COMPONENT_${UPPER_COMPONENT}_DEPENDS_${DISTRIBUTION_NAME_UPPER} ) 191 | foreach(DEP ${CPACK_COMPONENT_${UPPER_COMPONENT}_DEPENDS_${DISTRIBUTION_NAME_UPPER}}) 192 | set(DEPENDS "${DEPENDS}, ${DEP}") 193 | endforeach(DEP ${CPACK_COMPONENT_${UPPER_COMPONENT}_DEPENDS_${DISTRIBUTION_NAME_UPPER}}) 194 | else( CPACK_COMPONENT_${UPPER_COMPONENT}_DEPENDS_${DISTRIBUTION_NAME_UPPER} ) 195 | foreach(DEP ${CPACK_COMPONENT_${UPPER_COMPONENT}_DEPENDS}) 196 | set(DEPENDS "${DEPENDS}, ${DEP}") 197 | endforeach(DEP ${CPACK_COMPONENT_${UPPER_COMPONENT}_DEPENDS}) 198 | endif( CPACK_COMPONENT_${UPPER_COMPONENT}_DEPENDS_${DISTRIBUTION_NAME_UPPER} ) 199 | endif( CPACK_COMPONENT_${UPPER_COMPONENT}_DEPENDS_${DISTRIBUTION_NAME_UPPER}_${RELEASE_UPPER} ) 200 | 201 | set(RECOMMENDS) 202 | if( CPACK_COMPONENT_${UPPER_COMPONENT}_RECOMMENDS_${DISTRIBUTION_NAME_UPPER}_${RELEASE_UPPER} ) 203 | foreach(DEP ${CPACK_COMPONENT_${UPPER_COMPONENT}_RECOMMENDS_${DISTRIBUTION_NAME_UPPER}_${RELEASE_UPPER}}) 204 | set(RECOMMENDS "${RECOMMENDS} ${DEP}, ") 205 | endforeach(DEP ${CPACK_COMPONENT_${UPPER_COMPONENT}_RECOMMENDS_${DISTRIBUTION_NAME_UPPER}_${RELEASE_UPPER}}) 206 | else( CPACK_COMPONENT_${UPPER_COMPONENT}_RECOMMENDS_${DISTRIBUTION_NAME_UPPER}_${RELEASE_UPPER} ) 207 | if( CPACK_COMPONENT_${UPPER_COMPONENT}_RECOMMENDS_${DISTRIBUTION_NAME_UPPER} ) 208 | foreach(DEP ${CPACK_COMPONENT_${UPPER_COMPONENT}_RECOMMENDS_${DISTRIBUTION_NAME_UPPER}}) 209 | set(RECOMMENDS "${RECOMMENDS} ${DEP}, ") 210 | endforeach(DEP ${CPACK_COMPONENT_${UPPER_COMPONENT}_RECOMMENDS_${DISTRIBUTION_NAME_UPPER}}) 211 | else( CPACK_COMPONENT_${UPPER_COMPONENT}_RECOMMENDS_${DISTRIBUTION_NAME_UPPER} ) 212 | foreach(DEP ${CPACK_COMPONENT_${UPPER_COMPONENT}_RECOMMENDS}) 213 | set(RECOMMENDS "${RECOMMENDS} ${DEP}, ") 214 | endforeach(DEP ${CPACK_COMPONENT_${UPPER_COMPONENT}_RECOMMENDS}) 215 | endif( CPACK_COMPONENT_${UPPER_COMPONENT}_RECOMMENDS_${DISTRIBUTION_NAME_UPPER} ) 216 | endif( CPACK_COMPONENT_${UPPER_COMPONENT}_RECOMMENDS_${DISTRIBUTION_NAME_UPPER}_${RELEASE_UPPER} ) 217 | 218 | set(SUGGESTS) 219 | if( CPACK_COMPONENT_${UPPER_COMPONENT}_SUGGESTS_${DISTRIBUTION_NAME_UPPER}_${RELEASE_UPPER} ) 220 | foreach(DEP ${CPACK_COMPONENT_${UPPER_COMPONENT}_SUGGESTS_${DISTRIBUTION_NAME_UPPER}_${RELEASE_UPPER}}) 221 | set(SUGGESTS "${SUGGESTS} ${DEP}, ") 222 | endforeach(DEP ${CPACK_COMPONENT_${UPPER_COMPONENT}_SUGGESTS_${DISTRIBUTION_NAME_UPPER}_${RELEASE_UPPER}}) 223 | else( CPACK_COMPONENT_${UPPER_COMPONENT}_SUGGESTS_${DISTRIBUTION_NAME_UPPER}_${RELEASE_UPPER} ) 224 | if( CPACK_COMPONENT_${UPPER_COMPONENT}_SUGGESTS_${DISTRIBUTION_NAME_UPPER} ) 225 | foreach(DEP ${CPACK_COMPONENT_${UPPER_COMPONENT}_SUGGESTS_${DISTRIBUTION_NAME_UPPER}}) 226 | set(SUGGESTS "${SUGGESTS} ${DEP}, ") 227 | endforeach(DEP ${CPACK_COMPONENT_${UPPER_COMPONENT}_SUGGESTS_${DISTRIBUTION_NAME_UPPER}}) 228 | else( CPACK_COMPONENT_${UPPER_COMPONENT}_SUGGESTS_${DISTRIBUTION_NAME_UPPER} ) 229 | foreach(DEP ${CPACK_COMPONENT_${UPPER_COMPONENT}_SUGGESTS}) 230 | set(SUGGESTS "${SUGGESTS} ${DEP}, ") 231 | endforeach(DEP ${CPACK_COMPONENT_${UPPER_COMPONENT}_SUGGESTS}) 232 | endif( CPACK_COMPONENT_${UPPER_COMPONENT}_SUGGESTS_${DISTRIBUTION_NAME_UPPER} ) 233 | endif( CPACK_COMPONENT_${UPPER_COMPONENT}_SUGGESTS_${DISTRIBUTION_NAME_UPPER}_${RELEASE_UPPER} ) 234 | 235 | file(APPEND ${DEBIAN_CONTROL} "\n" 236 | "Package: ${CPACK_DEBIAN_PACKAGE_NAME}-${COMPONENT}\n" 237 | "Architecture: any\n" 238 | "Depends: ${DEPENDS}\n" 239 | "Recommends: ${RECOMMENDS}\n" 240 | "Suggests: ${SUGGESTS}\n" 241 | "Description: ${CPACK_PACKAGE_DISPLAY_NAME} ${CPACK_COMPONENT_${UPPER_COMPONENT}_DISPLAY_NAME}\n" 242 | "${DEB_LONG_DESCRIPTION}" 243 | " .\n" 244 | " ${CPACK_COMPONENT_${UPPER_COMPONENT}_DESCRIPTION}\n" 245 | ) 246 | endforeach(COMPONENT ${CPACK_COMPONENTS_ALL}) 247 | 248 | ############################################################################## 249 | # debian/copyright 250 | set(DEBIAN_COPYRIGHT ${DEBIAN_SOURCE_DIR}/debian/copyright) 251 | execute_process(COMMAND ${CMAKE_COMMAND} -E 252 | copy ${CPACK_RESOURCE_FILE_LICENSE} ${DEBIAN_COPYRIGHT} 253 | ) 254 | 255 | ############################################################################## 256 | # debian/rules 257 | set(DEBIAN_RULES ${DEBIAN_SOURCE_DIR}/debian/rules) 258 | file(WRITE ${DEBIAN_RULES} 259 | "#!/usr/bin/make -f\n" 260 | "\n" 261 | "BUILDDIR = build_dir\n" 262 | "\n" 263 | "build:\n" 264 | " mkdir $(BUILDDIR)\n" 265 | " cd $(BUILDDIR); cmake -DCMAKE_BUILD_TYPE=Release ${CPACK_DEBIAN_CMAKE_OPTIONS} -DCMAKE_INSTALL_PREFIX=/usr ..\n" 266 | " $(MAKE) -C $(BUILDDIR) preinstall\n" 267 | " touch build\n" 268 | "\n" 269 | "binary: binary-indep binary-arch\n" 270 | "\n" 271 | "binary-indep: build\n" 272 | "\n" 273 | "binary-arch: build\n" 274 | " cd $(BUILDDIR); cmake -DCOMPONENT=Unspecified -DCMAKE_INSTALL_PREFIX=../debian/tmp/usr -P cmake_install.cmake\n" 275 | " mkdir -p debian/tmp/DEBIAN\n" 276 | " dpkg-gensymbols -p${CPACK_DEBIAN_PACKAGE_NAME}\n" 277 | ) 278 | 279 | foreach(COMPONENT ${CPACK_COMPONENTS_ALL}) 280 | set(PATH debian/${COMPONENT}) 281 | file(APPEND ${DEBIAN_RULES} 282 | " cd $(BUILDDIR); cmake -DCOMPONENT=${COMPONENT} -DCMAKE_INSTALL_PREFIX=../${PATH}/usr -P cmake_install.cmake\n" 283 | " mkdir -p ${PATH}/DEBIAN\n" 284 | " dpkg-gensymbols -p${CPACK_DEBIAN_PACKAGE_NAME}-${COMPONENT} -P${PATH}\n" 285 | ) 286 | endforeach(COMPONENT ${CPACK_COMPONENTS_ALL}) 287 | 288 | file(APPEND ${DEBIAN_RULES} 289 | " dh_shlibdeps\n" 290 | " dh_strip\n" # for reducing size 291 | " dpkg-gencontrol -p${CPACK_DEBIAN_PACKAGE_NAME}\n" 292 | " dpkg --build debian/tmp ..\n" 293 | ) 294 | 295 | foreach(COMPONENT ${CPACK_COMPONENTS_ALL}) 296 | set(PATH debian/${COMPONENT}) 297 | file(APPEND ${DEBIAN_RULES} 298 | " dpkg-gencontrol -p${CPACK_DEBIAN_PACKAGE_NAME}-${COMPONENT} -P${PATH} -Tdebian/${COMPONENT}.substvars\n" 299 | " dpkg --build ${PATH} ..\n" 300 | ) 301 | endforeach(COMPONENT ${CPACK_COMPONENTS_ALL}) 302 | 303 | file(APPEND ${DEBIAN_RULES} 304 | "\n" 305 | "clean:\n" 306 | " rm -f build\n" 307 | " rm -rf $(BUILDDIR)\n" 308 | "\n" 309 | ".PHONY: binary binary-arch binary-indep clean\n" 310 | ) 311 | 312 | execute_process(COMMAND chmod +x ${DEBIAN_RULES}) 313 | 314 | ############################################################################## 315 | # debian/compat 316 | file(WRITE ${DEBIAN_SOURCE_DIR}/debian/compat "7") 317 | 318 | ############################################################################## 319 | # debian/source/format 320 | file(WRITE ${DEBIAN_SOURCE_DIR}/debian/source/format "3.0 (quilt)") 321 | 322 | ############################################################################## 323 | # debian/changelog 324 | set(DEBIAN_CHANGELOG ${DEBIAN_SOURCE_DIR}/debian/changelog) 325 | execute_process(COMMAND date -R OUTPUT_VARIABLE DATE_TIME) 326 | file(WRITE ${DEBIAN_CHANGELOG} 327 | "${CPACK_DEBIAN_PACKAGE_NAME} (${RELEASE_PACKAGE_VERSION}) ${RELEASE}; urgency=medium\n\n" 328 | " * Package built with CMake\n\n" 329 | "${CPACK_DEBIAN_CHANGELOG}" 330 | " -- ${CPACK_PACKAGE_CONTACT} ${DATE_TIME}" 331 | ) 332 | 333 | ############################################################################## 334 | # debuild -S 335 | if( DEB_SOURCE_CHANGES ) 336 | set(DEBUILD_OPTIONS "-sd") 337 | else() 338 | set(DEBUILD_OPTIONS "-sa") 339 | endif() 340 | set(SOURCE_CHANGES_FILE "${CPACK_DEBIAN_PACKAGE_NAME}_${RELEASE_PACKAGE_VERSION}_source.changes") 341 | set(DEB_SOURCE_CHANGES ${DEB_SOURCE_CHANGES} "${SOURCE_CHANGES_FILE}") 342 | add_custom_command(OUTPUT "${SOURCE_CHANGES_FILE}" COMMAND ${DEBUILD_EXECUTABLE} -S ${DEBUILD_OPTIONS} WORKING_DIRECTORY ${DEBIAN_SOURCE_DIR}) 343 | endforeach(RELEASE ${CPACK_DEBIAN_DISTRIBUTION_RELEASES}) 344 | 345 | ############################################################################## 346 | # dput ppa:your-lp-id/ppa 347 | add_custom_target(dput ${DPUT_EXECUTABLE} ${DPUT_HOST} ${DEB_SOURCE_CHANGES} DEPENDS ${DEB_SOURCE_CHANGES} WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/Debian) 348 | -------------------------------------------------------------------------------- /.cmake/Modules/FindCheck.cmake: -------------------------------------------------------------------------------- 1 | # - Try to find the CHECK libraries 2 | # Once done this will define 3 | # 4 | # CHECK_FOUND - system has check 5 | # CHECK_INCLUDE_DIRS - the check include directory 6 | # CHECK_LIBRARIES - check library 7 | # 8 | # Copyright (c) 2007 Daniel Gollub 9 | # Copyright (c) 2007-2009 Bjoern Ricks 10 | # 11 | # Redistribution and use is allowed according to the terms of the New 12 | # BSD license. 13 | # For details see the accompanying COPYING-CMAKE-SCRIPTS file. 14 | 15 | 16 | INCLUDE( FindPkgConfig ) 17 | 18 | IF ( Check_FIND_REQUIRED ) 19 | SET( _pkgconfig_REQUIRED "REQUIRED" ) 20 | ELSE( Check_FIND_REQUIRED ) 21 | SET( _pkgconfig_REQUIRED "" ) 22 | ENDIF ( Check_FIND_REQUIRED ) 23 | 24 | IF ( CHECK_MIN_VERSION ) 25 | PKG_SEARCH_MODULE( CHECK ${_pkgconfig_REQUIRED} check>=${CHECK_MIN_VERSION} ) 26 | ELSE ( CHECK_MIN_VERSION ) 27 | PKG_SEARCH_MODULE( CHECK ${_pkgconfig_REQUIRED} check ) 28 | ENDIF ( CHECK_MIN_VERSION ) 29 | 30 | # Look for CHECK include dir and libraries 31 | IF( NOT CHECK_FOUND AND NOT PKG_CONFIG_FOUND ) 32 | 33 | FIND_PATH( CHECK_INCLUDE_DIRS check.h ) 34 | 35 | FIND_LIBRARY( CHECK_LIBRARIES NAMES check ) 36 | 37 | IF ( CHECK_INCLUDE_DIRS AND CHECK_LIBRARIES ) 38 | SET( CHECK_FOUND 1 ) 39 | IF ( NOT Check_FIND_QUIETLY ) 40 | MESSAGE ( STATUS "Found CHECK: ${CHECK_LIBRARIES}" ) 41 | ENDIF ( NOT Check_FIND_QUIETLY ) 42 | ELSE ( CHECK_INCLUDE_DIRS AND CHECK_LIBRARIES ) 43 | IF ( Check_FIND_REQUIRED ) 44 | MESSAGE( FATAL_ERROR "Could NOT find CHECK" ) 45 | ELSE ( Check_FIND_REQUIRED ) 46 | IF ( NOT Check_FIND_QUIETLY ) 47 | MESSAGE( STATUS "Could NOT find CHECK" ) 48 | ENDIF ( NOT Check_FIND_QUIETLY ) 49 | ENDIF ( Check_FIND_REQUIRED ) 50 | ENDIF ( CHECK_INCLUDE_DIRS AND CHECK_LIBRARIES ) 51 | ENDIF( NOT CHECK_FOUND AND NOT PKG_CONFIG_FOUND ) 52 | 53 | # Hide advanced variables from CMake GUIs 54 | MARK_AS_ADVANCED( CHECK_INCLUDE_DIRS CHECK_LIBRARIES ) 55 | 56 | -------------------------------------------------------------------------------- /.cmake/Modules/PackageConfig.cmake: -------------------------------------------------------------------------------- 1 | 2 | function(extract_version version major minor patch extra) 3 | string(REGEX MATCH "([0-9]+)\\.([0-9]+)\\.([0-9]+)(.*)?" version_valid ${version}) 4 | if(version_valid) 5 | string(REGEX REPLACE "([0-9]+)\\.([0-9]+)\\.([0-9]+)(.*)?" "\\1;\\2;\\3;\\4" VERSION_MATCHES ${version}) 6 | list(GET VERSION_MATCHES 0 version_major) 7 | set(${major} ${version_major} PARENT_SCOPE) 8 | list(GET VERSION_MATCHES 1 version_minor) 9 | set(${minor} ${version_minor} PARENT_SCOPE) 10 | list(GET VERSION_MATCHES 2 version_patch) 11 | set(${patch} ${version_patch} PARENT_SCOPE) 12 | list(GET VERSION_MATCHES 3 version_extra) 13 | set(${extra} ${version_extra} PARENT_SCOPE) 14 | else(version_valid) 15 | message(AUTHOR_WARNING "Bad version ${version}; falling back to 0 (have you made an initial release?)") 16 | set(${major} "0" PARENT_SCOPE) 17 | set(${minor} "" PARENT_SCOPE) 18 | set(${patch} "" PARENT_SCOPE) 19 | set(${extra} "" PARENT_SCOPE) 20 | endif(version_valid) 21 | endfunction(extract_version) 22 | 23 | if (WIN32) 24 | set(CPACK_GENERATOR "ZIP") 25 | set(CPACK_SOURCE_GENERATOR "ZIP") 26 | else () 27 | set(CPACK_GENERATOR "TGZ") 28 | set(CPACK_SOURCE_GENERATOR "TGZ") 29 | endif () 30 | 31 | set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "Smart pointers library for the C programming language.") 32 | set(CPACK_PACKAGE_FILE_NAME "lib${CMAKE_PROJECT_NAME}-binary-${PROJECT_VERSION}") 33 | set(CPACK_SOURCE_PACKAGE_FILE_NAME "lib${CMAKE_PROJECT_NAME}-${PROJECT_VERSION}") 34 | set(CPACK_PACKAGE_INSTALL_DIRECTORY "lib${CMAKE_PROJECT_NAME}-${PROJECT_VERSION}") 35 | set(CPACK_PACKAGE_VENDOR "Franklin \"Snaipe\" Mathieu") 36 | set(CPACK_PACKAGE_CONTACT "Franklin \"Snaipe\" Mathieu ") 37 | set(CPACK_PACKAGE_VERSION "${PROJECT_VERSION}") 38 | 39 | if (WIN32) 40 | # add snapshot specific versioning information 41 | if (CPACK_DEBIAN_PACKAGE_TYPE STREQUAL "snapshot") 42 | execute_process(COMMAND date +%Y%m%d%0k%0M%0S%z OUTPUT_VARIABLE SNAPSHOT_DATE_TIME) 43 | set(CPACK_PACKAGE_VERSION "${PROJECT_VERSION}-snapshot-${SNAPSHOT_DATE_TIME}") 44 | STRING(REPLACE "\n" "" CPACK_PACKAGE_VERSION ${CPACK_PACKAGE_VERSION}) 45 | endif () 46 | endif () 47 | 48 | set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_SOURCE_DIR}/debian.copyright") 49 | extract_version(${PROJECT_VERSION} 50 | CPACK_PACKAGE_VERSION_MAJOR 51 | CPACK_PACKAGE_VERSION_MINOR 52 | CPACK_PACKAGE_VERSION_PATCH 53 | VERSION_EXTRA 54 | ) 55 | 56 | set(CPACK_PACKAGE_VERSION ${PROJECT_VERSION}) 57 | 58 | file(GLOB TRASH_FILES "${CMAKE_SOURCE_DIR}/*") 59 | set(KEEP_FILES 60 | "${CMAKE_SOURCE_DIR}/.cmake" 61 | "${CMAKE_SOURCE_DIR}/src" 62 | "${CMAKE_SOURCE_DIR}/include" 63 | "${CMAKE_SOURCE_DIR}/doc" 64 | "${CMAKE_SOURCE_DIR}/CMakeLists.txt" 65 | "${CMAKE_SOURCE_DIR}/README.md" 66 | "${CMAKE_SOURCE_DIR}/INSTALL.md" 67 | "${CMAKE_SOURCE_DIR}/LICENSE" 68 | "${CMAKE_SOURCE_DIR}/ChangeLog" 69 | "${CMAKE_SOURCE_DIR}/description.txt" 70 | ) 71 | list(REMOVE_ITEM TRASH_FILES ${KEEP_FILES}) 72 | # Escape any '.' characters 73 | string(REPLACE "." "\\\\." TRASH_FILES "${TRASH_FILES}") 74 | set(CPACK_SOURCE_IGNORE_FILES "${TRASH_FILES}") 75 | 76 | include(CPack) 77 | -------------------------------------------------------------------------------- /.cmake/Modules/UploadPPA.cmake: -------------------------------------------------------------------------------- 1 | ## 2 | # Copyright (c) 2012 Karsten Ohme 3 | # Based on a script from Daniel Pfeifer Copyright (c) 2010 4 | # 5 | # This script builds an Ubuntu/Debian source package with "make package_ubuntu". It also offers a convenient way to upload it by dput to Launchpad. 6 | #It assumes a working install and package_source configuration (CPACK_PACKAGE_* variables in CMakeLists.txt CMake configuration file) with all files in place. 7 | # Also a PGP key for signing the package is necessary. The key is referenced by the CPACK_DEBIAN_PACKAGE_MAINTAINER setting. For uploading the package to Launchpad this should be the Lauchpad PGP key. 8 | # You should also be familiar with the meaning of snapshot and release versions. See https://help.launchpad.net/Packaging/PPA/BuildingASourcePackage 9 | # 10 | # USAGE: INCLUDE IN PROJECT 11 | # 12 | # set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}) 13 | # include(UploadPPA) 14 | # Add the UploadPPA.cmake file to the projects source directory. 15 | # 16 | # 17 | # From the resulting dsc file in the Debian directory also a Ubuntu/Debian package can be build: 18 | # 19 | # dpkg-source -x foo.dsc 20 | # cd 21 | # fakeroot debian/rules binary 22 | # 23 | # When uploading it to Launchpad with dput you must be registered there and you must have a .dput.cf in place. Follow the instructions on https://help.launchpad.net/Packaging/PPA/Uploading 24 | # 25 | # Known problems: 26 | # 27 | # If you set the build type SET(CMAKE_BUILD_TYPE "Release") then the cmakeinstall.cmake file does not install the binary files 28 | # 29 | # 30 | # 31 | # CPACK_DEBIAN_PACKAGE_NAME - used as "Source" in control file, default TOLOWER "${CPACK_PACKAGE_NAME}" 32 | # CPACK_DEBIAN_PACKAGE_PRIORITY - used as "Priority" in control file, default "optional" 33 | # CPACK_DEBIAN_PACKAGE_SECTION - used as "Section" in control file, default "devel" 34 | # CPACK_DEBIAN_PACKAGE_HOMEPAGE - used in "Homepage" field in control file 35 | # CPACK_DEBIAN_BUILD_DEPENDS - use in "Build-Depends" field in control file, cmake is automatically added 36 | # CPACK_DEBIAN_PACKAGE_DEPENDS - used as "Depends" field in the control file, default "${shlibs:Depends}, ${misc:Depends} ${CPACK_PACKAGE_NAME} (= ${binary:Version}) " 37 | # for components. Instead of "binary:Version" "Source-Version" is used if CPACK_DEBIAN_PACKAGE_DISTRIBUTION is "dapper" 38 | # 39 | # CPACK_DEBIAN_PACKAGE_INSTALL - specifies which files have to be installed for the main package separated by ";". This is a space separated list. The file path must be absolute to the root directory of the installation 40 | # e.g. "/usr/lib/*.so". * wildcards can be used 41 | # CPACK_DEBIAN_PACKAGE_DOCS - specifies which files have to be installed for the main package separated by ";". This is a space separated list. The file path must be absolute to the root directory of the installation 42 | # e.g. "/usr/share/docs/${CPACK_DEBIAN_PACKAGE_NAME}-dev/README". * wildcards can be used 43 | # 44 | # CPACK_PACKAGE_DESCRIPTION_FILE - used main text in "Description" field of control file 45 | # CPACK_DEBIAN_PACKAGE_UPSTREAM_AUTHOR - used as upstream author in copyright file (format: Name ), default ${CPACK_DEBIAN_PACKAGE_MAINTAINER} 46 | # CPACK_DEBIAN_PACKAGE_UPSTREAM_AUTHOR_NAME - used as upstream author name in copyright file, default ${CPACK_DEBIAN_PACKAGE_HOMEPAGE} 47 | # CPACK_DEBIAN_PACKAGE_UPSTREAM_COPYRIGHT_YEAR - used as the copyright year in copyright file, default this year 48 | # CPACK_DEBIAN_PACKAGE_UPSTREAM_URL - used as upstream url in copyright file, default CPACK_DEBIAN_PACKAGE_HOMEPAGE 49 | # CPACK_DEBIAN_PACKAGE_LICENSE - used as license indicator for the copyright file generation, possible values gpl, lgpl, bsd, apache 50 | # CPACK_DEBIAN_PACKAGE_DISTRIBUTION - distribution name, default "precise" 51 | # 52 | # CPACK_DEBIAN_PACKAGE_RECOMMENDS - used as "Recommends" field in control file 53 | # CPACK_DEBIAN_PACKAGE_SUGGESTS - used as "Suggests" field in control file 54 | # CPACK_DEBIAN_PACKAGE_PREDEPENDS - used as "Pre-Depends" field in control file 55 | # CPACK_DEBIAN_PACKAGE_BREAKS - used as "Breaks" field in control file 56 | # CPACK_DEBIAN_PACKAGE_CONFLICTS - used as "Conflicts" field in control file 57 | # CPACK_DEBIAN_PACKAGE_REPLACES - used as "Replaces" field in control file 58 | # CPACK_DEBIAN_PACKAGE_ENHANCES - used as "Enhances" field in control file 59 | # 60 | # 61 | # 62 | # CPACK_COMPONENTS_ALL - list of additional components separated by ";" - used for the "Package" field in the control file for additional components of a package, e.g. for development files for a library this would be "dev" 63 | # The component must match the used components in the CMake file. The component is appended to ${CPACK_DEBIAN_PACKAGE_NAME} with a dash: e.g.: ${CPACK_DEBIAN_PACKAGE_NAME}-dev 64 | # CPACK_COMPONENT_${COMPONENT}_DISPLAY_NAME - used as additional short description for the "Description" field of additional packages. ${COMPONENT} must be in the list of CPACK_COMPONENTS_ALL, e.g. dev 65 | # CPACK_COMPONENT_${COMPONENT}_DESCRIPTION - used as additional description for the "Description" field of additional packages. ${COMPONENT} must be in the list of CPACK_COMPONENTS_ALL, e.g. dev 66 | # CPACK_COMPONENT_${COMPONENT}_DEPENDS - used for the "Depends" field of additional packages. ${COMPONENT} must be in the list of CPACK_COMPONENTS_ALL, e.g. dev 67 | # CPACK_COMPONENT_${COMPONENT}_SECTION - used for the "Section" field of additional packages. ${COMPONENT} must be in the list of CPACK_COMPONENTS_ALL, e.g. dev 68 | # CPACK_COMPONENT_${COMPONENT}_INSTALL - specifies which files have to be installed for this component separated by ";". The file path must be absolute to the root directory of the installation 69 | # e.g. "/usr/lib/*.so". * wildcards can be used 70 | # CPACK_COMPONENT_${COMPONENT}_DOCS - specifies which files have to be installed for this component separated by ";". The file path must be absolute to the root directory of the installation 71 | # e.g. "/usr/share/docs/${CPACK_DEBIAN_PACKAGE_NAME}/README". * wildcards can be used 72 | # CPACK_DEBIAN_PACKAGE_MANPAGES - specifies which files have to be installed as manual pages. Separated by ";". 73 | # CPACK_DEBIAN_CUSTOM_BUILD_COMMAND - A custom build command, e.g. create documentation with something like "make doc". The build artifact's path created somewhere in the build directory must be referenced in the CMake INSTALL command by ${CMAKE_CURRENT_BINARY_DIR} variable. E.g.: INSTALL(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/doc DESTINATION ${DOCUMENTATION_DIRECTORY} COMPONENT dev OPTIONAL) 74 | # The OPTIONAL keyword does not work under CMake 2.6, so you have to use a more difficult construct: 75 | # INSTALL( 76 | #CODE "FILE (GLOB_RECURSE ALL_DOCS \"${CMAKE_CURRENT_BINARY_DIR}/doc/html/*\")" 77 | #CODE "FILE (INSTALL DESTINATION \"\${CMAKE_INSTALL_PREFIX}/${DOCUMENTATION_DIRECTORY}/html\" TYPE FILE FILES \${ALL_DOCS})" 78 | #COMPONENT dev) 79 | # Here the "\" before ${CMAKE_INSTALL_PREFIX} is important, so this variable is resolved at runtime first. 80 | # 81 | # CPACK_DEBIAN_PACKAGE_MAINTAINER - used as "Maintainer" field in control and copyright file, default ${CPACK_PACKAGE_CONTACT}, also used as reference for the GPG signing key 82 | # CPACK_DEBIAN_PACKAGE_HOMEPAGE - used as "Homepage" in control file, default ${CPACK_PACKAGE_VENDOR} 83 | # CPACK_DEBIAN_PACKAGE_SNAPSHOT_HOMEPAGE - used as "Homepage" in control file if this is a snapshot build, default ${CPACK_PACKAGE_VENDOR} 84 | # CPACK_PACKAGE_DESCRIPTION_SUMMARY - used as first line of all "Description" fields for all packages in control file 85 | # 86 | # DPUT_HOST - used as host for dput for uploading the file to Launchpad 87 | # DPUT_SNAPSHOT_HOST - used as snapshot host for dput for uploading the file to Launchpad 88 | # CPACK_DEBIAN_PACKAGE_TYPE - used for determining the build type, "snapshot" or "release" is possible, default snapshot 89 | # 90 | # The format of the resulting versioning scheme is the following: ${CPACK_DEBIAN_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}-${CPACK_DEBIAN_PACKAGE_BUILD_NUMBER_PREFIX}${CPACK_DEBIAN_PACKAGE_BUILD_NUMBER}~${CPACK_DEBIAN_PACKAGE_DISTRIBUTION} 91 | #${CPACK_DEBIAN_PACKAGE_BUILD_NUMBER_PREFIX}${CPACK_DEBIAN_PACKAGE_BUILD_NUMBER}~${CPACK_DEBIAN_PACKAGE_DISTRIBUTION} is the Debian/Ubuntu revision. See http://www.debian.org/doc/debian-policy/ch-controlfields.html#s-f-Version. 92 | # An example is libfoo1-1.2.0-0ubuntu1~maverick 93 | # "0ubuntu1" stands for the first package in Ubuntu when there is no Debian package existing and "maverick" is the used Ubuntu series 94 | # 95 | # To generate always a unique code version for snapshots you must should also set ${CPACK_PACKAGE_VERSION} to a unique increasing package version number. This can be done by appending a [+SNAPSHOT] part to the package version number. The package version number cannot contain hyphens because a Debian/Ubuntu revision follows. 96 | # Assuming the libtool versioning scheme http://www.gnu.org/software/libtool/manual/html_node/Libtool-versioning.html an example could be: "1.2.0+1SNAPSHOT20110402031738+0200", when the current version is 1.2.0 and the next version in development is 1.2.1. The date format is using a variant of the ISO date format. 97 | # 98 | # CPACK_DEBIAN_PACKAGE_BUILD_NUMBER_PREFIX - used as a prefix for the build number, default "" 99 | # CPACK_DEBIAN_PACKAGE_BUILD_NUMBER - used for the build number, default 1 100 | # CPACK_DEBIAN_NATIVE_PACKAGE - if set a native package is build, default not set 101 | # 102 | # 103 | ## 104 | 105 | find_program(DEBUILD_EXECUTABLE debuild) 106 | find_program(DPUT_EXECUTABLE dput) 107 | 108 | if(NOT DEBUILD_EXECUTABLE OR NOT DPUT_EXECUTABLE) 109 | MESSAGE(WARNING "${DEBUILD_EXECUTABLE} or ${DPUT_EXECUTABLE} not installed.") 110 | return() 111 | endif(NOT DEBUILD_EXECUTABLE OR NOT DPUT_EXECUTABLE) 112 | 113 | # set default package type 114 | IF(NOT CPACK_DEBIAN_PACKAGE_TYPE) 115 | set(CPACK_DEBIAN_PACKAGE_TYPE "snapshot") 116 | ENDIF(NOT CPACK_DEBIAN_PACKAGE_TYPE) 117 | 118 | # set default distribution 119 | IF(NOT CPACK_DEBIAN_PACKAGE_DISTRIBUTION) 120 | set(CPACK_DEBIAN_PACKAGE_DISTRIBUTION "precise") 121 | ENDIF(NOT CPACK_DEBIAN_PACKAGE_DISTRIBUTION) 122 | 123 | # Set the version name 124 | set(VERSION_NAME "${CPACK_PACKAGE_VERSION}-${CPACK_DEBIAN_PACKAGE_BUILD_NUMBER_PREFIX}${CPACK_DEBIAN_PACKAGE_BUILD_NUMBER}~${CPACK_DEBIAN_PACKAGE_DISTRIBUTION}") 125 | 126 | # DEBIAN/control 127 | # debian policy enforce lower case for package name 128 | # Package: (mandatory) 129 | IF(NOT CPACK_DEBIAN_PACKAGE_NAME) 130 | STRING(TOLOWER "${CPACK_PACKAGE_NAME}" CPACK_DEBIAN_PACKAGE_NAME) 131 | ENDIF(NOT CPACK_DEBIAN_PACKAGE_NAME) 132 | 133 | # Maintainer: 134 | IF(NOT CPACK_DEBIAN_PACKAGE_MAINTAINER) 135 | set(CPACK_DEBIAN_PACKAGE_MAINTAINER ${CPACK_DEBIAN_PACKAGE_HOMEPAGE}) 136 | ENDIF(NOT CPACK_DEBIAN_PACKAGE_MAINTAINER) 137 | 138 | # Homepage: 139 | IF(NOT CPACK_DEBIAN_PACKAGE_HOMEPAGE) 140 | ENDIF(NOT CPACK_DEBIAN_PACKAGE_HOMEPAGE) 141 | 142 | # Section: (recommended) 143 | IF(NOT CPACK_DEBIAN_PACKAGE_SECTION) 144 | SET(CPACK_DEBIAN_PACKAGE_SECTION "devel") 145 | ENDIF(NOT CPACK_DEBIAN_PACKAGE_SECTION) 146 | 147 | # Priority: (recommended) 148 | IF(NOT CPACK_DEBIAN_PACKAGE_PRIORITY) 149 | SET(CPACK_DEBIAN_PACKAGE_PRIORITY "optional") 150 | ENDIF(NOT CPACK_DEBIAN_PACKAGE_PRIORITY) 151 | 152 | # Section: 153 | set(CPACK_DEBIAN_PACKAGE_DEPENDS "\${shlibs:Depends}, \${misc:Depends}") 154 | 155 | # Description: 156 | file(STRINGS ${CPACK_PACKAGE_DESCRIPTION_FILE} DESC_LINES) 157 | foreach(LINE ${DESC_LINES}) 158 | set(DEB_LONG_DESCRIPTION "${DEB_LONG_DESCRIPTION} ${LINE}\n") 159 | endforeach(LINE ${DESC_LINES}) 160 | 161 | file(REMOVE_RECURSE ${CMAKE_BINARY_DIR}/Debian) 162 | set(DEBIAN_SOURCE_DIR ${CMAKE_BINARY_DIR}/Debian/${CPACK_DEBIAN_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}) 163 | 164 | file(MAKE_DIRECTORY ${DEBIAN_SOURCE_DIR}/debian) 165 | 166 | ############################################################################## 167 | # debian/control 168 | set(DEBIAN_CONTROL ${DEBIAN_SOURCE_DIR}/debian/control) 169 | file(WRITE ${DEBIAN_CONTROL} 170 | "Source: ${CPACK_DEBIAN_PACKAGE_NAME}\n" 171 | "Section: ${CPACK_DEBIAN_PACKAGE_SECTION}\n" 172 | "Priority: ${CPACK_DEBIAN_PACKAGE_PRIORITY}\n" 173 | "Maintainer: ${CPACK_DEBIAN_PACKAGE_MAINTAINER}\n" 174 | "Build-Depends: " 175 | ) 176 | 177 | foreach(DEP ${CPACK_DEBIAN_BUILD_DEPENDS}) 178 | file(APPEND ${DEBIAN_CONTROL} "${DEP}, ") 179 | endforeach(DEP ${CPACK_DEBIAN_BUILD_DEPENDS}) 180 | 181 | file(APPEND ${DEBIAN_CONTROL} "cmake\n" 182 | "Standards-Version: 3.8.4\n" 183 | ) 184 | 185 | 186 | IF(CPACK_DEBIAN_PACKAGE_TYPE STREQUAL "snapshot") 187 | file(APPEND ${DEBIAN_CONTROL} "Homepage: ${CPACK_DEBIAN_PACKAGE_SNAPSHOT_HOMEPAGE}\n") 188 | ELSE(CPACK_DEBIAN_PACKAGE_TYPE STREQUAL "snapshot") 189 | file(APPEND ${DEBIAN_CONTROL} "Homepage: ${CPACK_DEBIAN_PACKAGE_HOMEPAGE}\n") 190 | ENDIF(CPACK_DEBIAN_PACKAGE_TYPE STREQUAL "snapshot") 191 | 192 | file(APPEND ${DEBIAN_CONTROL} 193 | "\n" 194 | "Package: ${CPACK_DEBIAN_PACKAGE_NAME}\n" 195 | "Architecture: any\n" 196 | "Depends: ${CPACK_DEBIAN_PACKAGE_DEPENDS}\n" 197 | ) 198 | 199 | # Recommends: 200 | IF(CPACK_DEBIAN_PACKAGE_RECOMMENDS) 201 | file(APPEND ${DEBIAN_CONTROL} 202 | "Recommends: ${CPACK_DEBIAN_PACKAGE_RECOMMENDS}\n" 203 | ) 204 | ENDIF(CPACK_DEBIAN_PACKAGE_RECOMMENDS) 205 | 206 | # Suggests 207 | IF(CPACK_DEBIAN_PACKAGE_SUGGESTS) 208 | file(APPEND ${DEBIAN_CONTROL} 209 | "Suggests: ${CPACK_DEBIAN_PACKAGE_SUGGESTS}\n" 210 | ) 211 | ENDIF(CPACK_DEBIAN_PACKAGE_SUGGESTS) 212 | 213 | # Pre-Depends: 214 | IF(CPACK_DEBIAN_PACKAGE_PREDEPENDS) 215 | file(APPEND ${DEBIAN_CONTROL} 216 | "Pre-Depends: ${CPACK_DEBIAN_PACKAGE_PREDEPENDS}\n" 217 | ) 218 | ENDIF(CPACK_DEBIAN_PACKAGE_PREDEPENDS) 219 | 220 | # Conflicts: 221 | IF(CPACK_DEBIAN_PACKAGE_CONFLICTS) 222 | file(APPEND ${DEBIAN_CONTROL} 223 | "Conflicts: ${CPACK_DEBIAN_PACKAGE_CONFLICTS}\n" 224 | ) 225 | ENDIF(CPACK_DEBIAN_PACKAGE_CONFLICTS) 226 | 227 | # Enhances: 228 | IF(CPACK_DEBIAN_PACKAGE_ENHANCES) 229 | file(APPEND ${DEBIAN_CONTROL} 230 | "Enhances: ${CPACK_DEBIAN_PACKAGE_ENHANCES}\n" 231 | ) 232 | ENDIF(CPACK_DEBIAN_PACKAGE_ENHANCES) 233 | 234 | # Replaces: 235 | IF(CPACK_DEBIAN_PACKAGE_REPLACES) 236 | file(APPEND ${DEBIAN_CONTROL} 237 | "Replaces: ${CPACK_DEBIAN_PACKAGE_REPLACES}\n" 238 | ) 239 | ENDIF(CPACK_DEBIAN_PACKAGE_REPLACES) 240 | 241 | file(APPEND ${DEBIAN_CONTROL} 242 | "Description: ${CPACK_PACKAGE_DESCRIPTION_SUMMARY}\n" 243 | "${DEB_LONG_DESCRIPTION}" 244 | ) 245 | 246 | foreach(COMPONENT ${CPACK_COMPONENTS_ALL}) 247 | string(TOUPPER ${COMPONENT} UPPER_COMPONENT) 248 | set(DEPENDS "${CPACK_DEBIAN_PACKAGE_NAME}") 249 | IF(CPACK_DEBIAN_PACKAGE_DISTRIBUTION STREQUAL "dapper") 250 | set(DEPENDS "${DEPENDS} (= \${Source-Version})") 251 | ELSE(CPACK_DEBIAN_PACKAGE_DISTRIBUTION STREQUAL "dapper") 252 | set(DEPENDS "${DEPENDS} (= \${binary:Version})") 253 | ENDIF(CPACK_DEBIAN_PACKAGE_DISTRIBUTION STREQUAL "dapper") 254 | foreach(DEP ${CPACK_COMPONENT_${UPPER_COMPONENT}_DEPENDS}) 255 | set(DEPENDS "${DEPENDS}, ${CPACK_DEBIAN_PACKAGE_NAME}-${DEP}") 256 | endforeach(DEP ${CPACK_COMPONENT_${UPPER_COMPONENT}_DEPENDS}) 257 | file(APPEND ${DEBIAN_CONTROL} "\n" 258 | "Package: ${CPACK_DEBIAN_PACKAGE_NAME}-${COMPONENT}\n" 259 | "Section: ${CPACK_COMPONENT_${UPPER_COMPONENT}_SECTION}\n" 260 | "Architecture: any\n" 261 | "Depends: ${DEPENDS}\n" 262 | "Description: ${CPACK_PACKAGE_DESCRIPTION_SUMMARY}" 263 | ": ${CPACK_COMPONENT_${UPPER_COMPONENT}_DISPLAY_NAME}\n" 264 | "${DEB_LONG_DESCRIPTION}" 265 | " .\n" 266 | " ${CPACK_COMPONENT_${UPPER_COMPONENT}_DESCRIPTION}\n" 267 | ) 268 | endforeach(COMPONENT ${CPACK_COMPONENTS_ALL}) 269 | 270 | ############################################################################## 271 | # debian/copyright 272 | set(DEBIAN_COPYRIGHT ${DEBIAN_SOURCE_DIR}/debian/copyright) 273 | 274 | IF(NOT CPACK_DEBIAN_PACKAGE_LICENSE) 275 | set(CPACK_DEBIAN_PACKAGE_LICENSE gpl) 276 | ENDIF(NOT CPACK_DEBIAN_PACKAGE_LICENSE) 277 | 278 | IF(NOT CPACK_DEBIAN_PACKAGE_UPSTREAM_AUTHOR) 279 | set(CPACK_DEBIAN_PACKAGE_UPSTREAM_AUTHOR ${CPACK_DEBIAN_PACKAGE_MAINTAINER}) 280 | ENDIF(NOT CPACK_DEBIAN_PACKAGE_UPSTREAM_AUTHOR) 281 | 282 | IF(NOT CPACK_DEBIAN_PACKAGE_UPSTREAM_AUTHOR_NAME) 283 | set(CPACK_DEBIAN_PACKAGE_UPSTREAM_AUTHOR_NAME ${CPACK_DEBIAN_PACKAGE_HOMEPAGE}) 284 | ENDIF(NOT CPACK_DEBIAN_PACKAGE_UPSTREAM_AUTHOR_NAME) 285 | 286 | IF(NOT CPACK_DEBIAN_PACKAGE_UPSTREAM_URL) 287 | set(CPACK_DEBIAN_PACKAGE_UPSTREAM_URL ${CPACK_DEBIAN_PACKAGE_HOMEPAGE}) 288 | ENDIF(NOT CPACK_DEBIAN_PACKAGE_UPSTREAM_URL) 289 | 290 | IF(NOT CPACK_DEBIAN_PACKAGE_UPSTREAM_COPYRIGHT_YEAR) 291 | execute_process(COMMAND date +%Y OUTPUT_VARIABLE CPACK_DEBIAN_PACKAGE_UPSTREAM_COPYRIGHT_YEAR) 292 | STRING(REPLACE "\n" "" CPACK_DEBIAN_PACKAGE_UPSTREAM_COPYRIGHT_YEAR ${CPACK_DEBIAN_PACKAGE_UPSTREAM_COPYRIGHT_YEAR}) 293 | ENDIF(NOT CPACK_DEBIAN_PACKAGE_UPSTREAM_COPYRIGHT_YEAR) 294 | 295 | execute_process(COMMAND date +%Y OUTPUT_VARIABLE CPACK_DEBIAN_PACKAGE_YEAR) 296 | STRING(REPLACE "\n" "" CPACK_DEBIAN_PACKAGE_YEAR ${CPACK_DEBIAN_PACKAGE_YEAR}) 297 | 298 | execute_process(COMMAND date -R OUTPUT_VARIABLE CPACK_DEBIAN_PACKAGE_DATE) 299 | STRING(REPLACE "\n" "" CPACK_DEBIAN_PACKAGE_DATE ${CPACK_DEBIAN_PACKAGE_DATE}) 300 | 301 | set(POSSIBLE_LICENSES gpl lgpl bsd apache expat) 302 | list(FIND POSSIBLE_LICENSES ${CPACK_DEBIAN_PACKAGE_LICENSE} CPACK_DEBIAN_PACKAGE_LICENSE_FOUND) 303 | 304 | IF(CPACK_DEBIAN_PACKAGE_LICENSE_FOUND EQUAL "-1") 305 | message(FATAL_ERROR "License ${CPACK_DEBIAN_PACKAGE_LICENSE} is unknown.") 306 | ENDIF(CPACK_DEBIAN_PACKAGE_LICENSE_FOUND EQUAL "-1") 307 | 308 | find_path(COPYRIGHT_FILES_DIRECTORY copyright.${CPACK_DEBIAN_PACKAGE_LICENSE} PATHS ${CMAKE_MODULE_PATH}) 309 | execute_process(COMMAND ${CMAKE_COMMAND} -E 310 | copy ${COPYRIGHT_FILES_DIRECTORY}/copyright.${CPACK_DEBIAN_PACKAGE_LICENSE} ${DEBIAN_COPYRIGHT} 311 | ) 312 | 313 | # Here also CONFIGURE_FILE might be better 314 | FILE(READ ${DEBIAN_COPYRIGHT} COPYRIGHT_TEMP) 315 | STRING(REPLACE "" ${CPACK_DEBIAN_PACKAGE_MAINTAINER} COPYRIGHT_TEMP ${COPYRIGHT_TEMP}) 316 | STRING(REPLACE "" ${CPACK_DEBIAN_PACKAGE_DATE} COPYRIGHT_TEMP ${COPYRIGHT_TEMP}) 317 | STRING(REPLACE "" ${CPACK_DEBIAN_PACKAGE_YEAR} COPYRIGHT_TEMP ${COPYRIGHT_TEMP}) 318 | STRING(REPLACE "" ${CPACK_DEBIAN_PACKAGE_UPSTREAM_URL} COPYRIGHT_TEMP ${COPYRIGHT_TEMP}) 319 | STRING(REPLACE "" ${CPACK_DEBIAN_PACKAGE_UPSTREAM_AUTHOR} COPYRIGHT_TEMP ${COPYRIGHT_TEMP}) 320 | STRING(REPLACE "" ${CPACK_DEBIAN_PACKAGE_UPSTREAM_COPYRIGHT_YEAR} COPYRIGHT_TEMP ${COPYRIGHT_TEMP}) 321 | STRING(REPLACE "" ${CPACK_DEBIAN_PACKAGE_UPSTREAM_AUTHOR_NAME} COPYRIGHT_TEMP ${COPYRIGHT_TEMP}) 322 | FILE(WRITE ${DEBIAN_COPYRIGHT} ${COPYRIGHT_TEMP}) 323 | 324 | ############################################################################## 325 | # debian/${CPACK_DEBIAN_PACKAGE_NAME}.install 326 | set(DEBIAN_INSTALL_FILE ${DEBIAN_SOURCE_DIR}/debian/${CPACK_DEBIAN_PACKAGE_NAME}.install) 327 | foreach(INSTALL_UNIT ${CPACK_DEBIAN_PACKAGE_INSTALL}) 328 | file(APPEND ${DEBIAN_INSTALL_FILE} "debian/tmp${INSTALL_UNIT}\n") 329 | endforeach(INSTALL_UNIT ${CPACK_DEBIAN_PACKAGE_INSTALL}) 330 | 331 | ############################################################################## 332 | # debian/${CPACK_DEBIAN_PACKAGE_NAME}.docs 333 | set(DEBIAN_DOCS_FILE ${DEBIAN_SOURCE_DIR}/debian/${CPACK_DEBIAN_PACKAGE_NAME}.docs) 334 | foreach(INSTALL_UNIT ${CPACK_DEBIAN_PACKAGE_DOCS}) 335 | file(APPEND ${DEBIAN_DOCS_FILE} "debian/tmp${INSTALL_UNIT}\n") 336 | endforeach(INSTALL_UNIT ${CPACK_DEBIAN_PACKAGE_DOCS}) 337 | 338 | ############################################################################## 339 | # debian/${CPACK_DEBIAN_PACKAGE_NAME}.manpages 340 | set(DEBIAN_MANPAGES_FILE ${DEBIAN_SOURCE_DIR}/debian/${CPACK_DEBIAN_PACKAGE_NAME}.manpages) 341 | foreach(INSTALL_UNIT ${CPACK_DEBIAN_PACKAGE_MANPAGES}) 342 | file(APPEND ${DEBIAN_MANPAGES_FILE} "debian/tmp${INSTALL_UNIT}\n") 343 | endforeach(INSTALL_UNIT ${CPACK_DEBIAN_PACKAGE_MANPAGES}) 344 | 345 | foreach(COMPONENT ${CPACK_COMPONENTS_ALL}) 346 | string(TOUPPER ${COMPONENT} UPPER_COMPONENT) 347 | 348 | ############################################################################## 349 | # debian/${CPACK_DEBIAN_PACKAGE_NAME}-${COMPONENT}.install 350 | set(DEBIAN_INSTALL_FILE ${DEBIAN_SOURCE_DIR}/debian/${CPACK_DEBIAN_PACKAGE_NAME}-${COMPONENT}.install) 351 | foreach(INSTALL_UNIT ${CPACK_COMPONENT_${UPPER_COMPONENT}_INSTALL}) 352 | file(APPEND ${DEBIAN_INSTALL_FILE} "debian/tmp${INSTALL_UNIT}\n") 353 | endforeach(INSTALL_UNIT ${CPACK_COMPONENT_${UPPER_COMPONENT}_INSTALL}) 354 | 355 | ############################################################################## 356 | # debian/${CPACK_DEBIAN_PACKAGE_NAME}-${COMPONENT}.docs 357 | set(DEBIAN_DOCS_FILE ${DEBIAN_SOURCE_DIR}/debian/${CPACK_DEBIAN_PACKAGE_NAME}-${COMPONENT}.docs) 358 | foreach(INSTALL_UNIT ${CPACK_COMPONENT_${UPPER_COMPONENT}_DOCS}) 359 | file(APPEND ${DEBIAN_DOCS_FILE} "debian/tmp${INSTALL_UNIT}\n") 360 | endforeach(INSTALL_UNIT ${CPACK_COMPONENT_${UPPER_COMPONENT}_DOCS}) 361 | 362 | ############################################################################## 363 | # debian/${CPACK_DEBIAN_PACKAGE_NAME}-${COMPONENT}.manpages 364 | set(DEBIAN_MANPAGES_FILE ${DEBIAN_SOURCE_DIR}/debian/${CPACK_DEBIAN_PACKAGE_NAME}-${COMPONENT}.manpages) 365 | foreach(INSTALL_UNIT ${CPACK_COMPONENT_${UPPER_COMPONENT}_MANPAGES}) 366 | file(APPEND ${DEBIAN_MANPAGES_FILE} "debian/tmp${INSTALL_UNIT}\n") 367 | endforeach(INSTALL_UNIT ${CPACK_COMPONENT_${UPPER_COMPONENT}_MANPAGES}) 368 | 369 | endforeach(COMPONENT ${CPACK_COMPONENTS_ALL}) 370 | 371 | ############################################################################## 372 | # debian/rules 373 | set(DEBIAN_RULES ${DEBIAN_SOURCE_DIR}/debian/rules) 374 | file(WRITE ${DEBIAN_RULES} 375 | "#!/usr/bin/make -f\n" 376 | "\n" 377 | "BUILDDIR = build_dir\n" 378 | "\n" 379 | "build:\n" 380 | " mkdir $(BUILDDIR)\n" 381 | " cd $(BUILDDIR); cmake ..\n" 382 | " cd $(BUILDDIR); ${CPACK_DEBIAN_CUSTOM_BUILD_COMMAND}\n" 383 | " make -C $(BUILDDIR) preinstall\n" 384 | " touch build\n" 385 | "\n" 386 | "binary: binary-indep binary-arch\n" 387 | "\n" 388 | "binary-indep: build\n" 389 | "\n" 390 | "binary-arch: build\n" 391 | " cd $(BUILDDIR); cmake -DCMAKE_INSTALL_PREFIX=../debian/tmp/usr -P cmake_install.cmake\n" 392 | " dh_testdir\n" 393 | " dh_testroot\n" 394 | " dh_installchangelogs\n" 395 | " dh_installdocs\n" 396 | " dh_installman\n" 397 | " dh_install\n" 398 | " dh_link\n" 399 | " dh_strip\n" 400 | " dh_compress\n" 401 | " dh_fixperms\n" 402 | " dh_listpackages\n" 403 | " dh_makeshlibs\n" 404 | " dh_gencontrol\n" 405 | " dh_md5sums\n" 406 | " dh_builddeb\n" 407 | ) 408 | 409 | # sh_libs is not resolved. Maybe OK, maybe wrong. This is a try. 410 | # " dpkg-shlibdeps -e./debian/tmp/usr/lib/libglobalplatform.so\n" 411 | # " dh_shlibdeps\n" 412 | # " mkdir debian/tmp/DEBIAN\n" 413 | #" dpkg-gensymbols -plibglobalplatform\n" 414 | # " dpkg-shlibdeps -elibglobalplatform\n" 415 | # " dpkg-gencontrol -p${CPACK_DEBIAN_PACKAGE_NAME}\n" 416 | # " dpkg --build debian/tmp ..\n" 417 | 418 | 419 | foreach(COMPONENT ${CPACK_COMPONENTS_ALL}) 420 | set(PATH debian/tmp_${COMPONENT}) 421 | set(PACKAGE ${CPACK_DEBIAN_PACKAGE_NAME}-${COMPONENT}) 422 | file(APPEND ${DEBIAN_RULES} 423 | " cd $(BUILDDIR); cmake -DCOMPONENT=${COMPONENT} -DCMAKE_INSTALL_PREFIX=../${PATH}/usr -P cmake_install.cmake\n" 424 | " dh_testdir\n" 425 | " dh_testroot\n" 426 | " dh_installchangelogs\n" 427 | " dh_installdocs\n" 428 | " dh_installman\n" 429 | " dh_install\n" 430 | " dh_link\n" 431 | " dh_strip\n" 432 | " dh_compress\n" 433 | " dh_fixperms\n" 434 | " dh_listpackages\n" 435 | " dh_makeshlibs\n" 436 | " dh_gencontrol\n" 437 | " dh_md5sums\n" 438 | " dh_builddeb\n" 439 | ) 440 | endforeach(COMPONENT ${CPACK_COMPONENTS_ALL}) 441 | 442 | # sh_libs is not resolved. Maybe OK, maybe wrong. This is a try. 443 | # " dpkg-shlibdeps -e./debian/tmp/usr/lib/libglobalplatform.so\n" 444 | # " dh_shlibdeps\n" 445 | # " mkdir ${PATH}/DEBIAN\n" 446 | # " dh_shlibdeps -L libglobalplatform6 -l ../debian/tmp/usr/lib\n" 447 | # " dpkg-gensymbols -plibglobalplatform -P${PATH}\n" 448 | # " dpkg-shlibdeps -elibglobalplatform\n" 449 | # " dpkg-gencontrol -p${PACKAGE} -P${PATH}\n" 450 | # " dpkg --build ${PATH} ..\n" 451 | 452 | file(APPEND ${DEBIAN_RULES} 453 | "\n" 454 | "clean:\n" 455 | " rm -f build\n" 456 | " rm -rf $(BUILDDIR)\n" 457 | "\n" 458 | ".PHONY: binary binary-arch binary-indep clean\n" 459 | ) 460 | 461 | execute_process(COMMAND chmod +x ${DEBIAN_RULES}) 462 | 463 | ############################################################################## 464 | # debian/compat - 5 is used to also support dapper 465 | file(WRITE ${DEBIAN_SOURCE_DIR}/debian/compat "5") 466 | 467 | ############################################################################## 468 | # debian/source/format 469 | IF(CPACK_DEBIAN_NATIVE_PACKAGE) 470 | file(WRITE ${DEBIAN_SOURCE_DIR}/debian/source/format "3.0 (native)") 471 | ELSE(CPACK_DEBIAN_NATIVE_PACKAGE) 472 | file(WRITE ${DEBIAN_SOURCE_DIR}/debian/source/format "3.0 (quilt)") 473 | ENDIF(CPACK_DEBIAN_NATIVE_PACKAGE) 474 | 475 | ############################################################################## 476 | # debian/changelog 477 | 478 | 479 | set(DEBIAN_CHANGELOG ${DEBIAN_SOURCE_DIR}/debian/changelog) 480 | execute_process(COMMAND date -R OUTPUT_VARIABLE DATE_TIME) 481 | 482 | 483 | file(WRITE ${DEBIAN_CHANGELOG} 484 | "${CPACK_DEBIAN_PACKAGE_NAME} (${VERSION_NAME}) ${CPACK_DEBIAN_PACKAGE_DISTRIBUTION}; urgency=low\n\n" 485 | " * Package built with CMake\n\n" 486 | " -- ${CPACK_DEBIAN_PACKAGE_MAINTAINER} ${DATE_TIME}" 487 | ) 488 | 489 | #INSTALL(FILES ${CMAKE_CURRENT_BUILD_DIR}/*.so DESTINATION lib${LIB_SUFFIX}) 490 | 491 | ############################################################################## 492 | # debuild -S 493 | set(DEB_SOURCE_CHANGES 494 | ${CPACK_DEBIAN_PACKAGE_NAME}_${VERSION_NAME}_source.changes 495 | ) 496 | 497 | add_custom_command(OUTPUT ${CMAKE_BINARY_DIR}/Debian/${DEB_SOURCE_CHANGES} 498 | COMMAND ${DEBUILD_EXECUTABLE} -S 499 | DEPENDS ${CMAKE_BINARY_DIR}/Debian/${CPACK_DEBIAN_PACKAGE_NAME}_${CPACK_PACKAGE_VERSION}.orig.tar.gz 500 | WORKING_DIRECTORY ${DEBIAN_SOURCE_DIR} 501 | ) 502 | 503 | IF(${CPACK_DEBIAN_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION} STREQUAL ${CPACK_SOURCE_PACKAGE_FILE_NAME}) 504 | add_custom_command(OUTPUT ${CMAKE_BINARY_DIR}/Debian/${CPACK_DEBIAN_PACKAGE_NAME}_${CPACK_PACKAGE_VERSION}.orig.tar.gz 505 | COMMAND make -C ${CMAKE_BINARY_DIR} package_source 506 | COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_BINARY_DIR}/${CPACK_SOURCE_PACKAGE_FILE_NAME}.tar.gz ${CMAKE_BINARY_DIR}/Debian/${CPACK_DEBIAN_PACKAGE_NAME}_${CPACK_PACKAGE_VERSION}.orig.tar.gz 507 | COMMAND tar xzf ${CMAKE_BINARY_DIR}/Debian/${CPACK_DEBIAN_PACKAGE_NAME}_${CPACK_PACKAGE_VERSION}.orig.tar.gz -C ${CMAKE_BINARY_DIR}/Debian/ 508 | WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR} 509 | ) 510 | ELSE(${CPACK_DEBIAN_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION} STREQUAL ${CPACK_SOURCE_PACKAGE_FILE_NAME}) 511 | add_custom_command(OUTPUT ${CMAKE_BINARY_DIR}/Debian/${CPACK_DEBIAN_PACKAGE_NAME}_${CPACK_PACKAGE_VERSION}.orig.tar.gz 512 | COMMAND make -C ${CMAKE_BINARY_DIR} package_source 513 | COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_BINARY_DIR}/${CPACK_SOURCE_PACKAGE_FILE_NAME}.tar.gz ${CMAKE_BINARY_DIR}/Debian/${CPACK_DEBIAN_PACKAGE_NAME}_${CPACK_PACKAGE_VERSION}.orig.tar.gz 514 | COMMAND tar xzf ${CMAKE_BINARY_DIR}/Debian/${CPACK_DEBIAN_PACKAGE_NAME}_${CPACK_PACKAGE_VERSION}.orig.tar.gz -C ${CMAKE_BINARY_DIR}/Debian/ 515 | COMMAND cp -unR ${CMAKE_BINARY_DIR}/Debian/${CPACK_SOURCE_PACKAGE_FILE_NAME}/* ${CMAKE_BINARY_DIR}/Debian/${CPACK_DEBIAN_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION} 516 | WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR} 517 | ) 518 | ENDIF(${CPACK_DEBIAN_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION} STREQUAL ${CPACK_SOURCE_PACKAGE_FILE_NAME}) 519 | 520 | add_custom_target(package_ubuntu 521 | DEPENDS ${CMAKE_BINARY_DIR}/Debian/${CPACK_DEBIAN_PACKAGE_NAME}_${CPACK_PACKAGE_VERSION}.orig.tar.gz ${CMAKE_BINARY_DIR}/Debian/${DEB_SOURCE_CHANGES} 522 | WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/Debian 523 | ) 524 | 525 | ############################################################################## 526 | # dput ppa:your-lp-id/ppa 527 | IF(CPACK_DEBIAN_PACKAGE_TYPE STREQUAL "snapshot") 528 | set(USED_DPUT_HOST ${DPUT_SNAPSHOT_HOST}) 529 | ELSE(CPACK_DEBIAN_PACKAGE_TYPE STREQUAL "snapshot") 530 | set(USED_DPUT_HOST ${DPUT_HOST}) 531 | ENDIF(CPACK_DEBIAN_PACKAGE_TYPE STREQUAL "snapshot") 532 | 533 | 534 | add_custom_target(dput ${DPUT_EXECUTABLE} ${USED_DPUT_HOST} ${DEB_SOURCE_CHANGES} 535 | DEPENDS ${CMAKE_BINARY_DIR}/Debian/${DEB_SOURCE_CHANGES} 536 | WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/Debian 537 | ) 538 | 539 | # Also clean Debian directory 540 | set_directory_properties(PROPERTIES ADDITIONAL_MAKE_CLEAN_FILES ${DEBIAN_SOURCE_DIR}) 541 | -------------------------------------------------------------------------------- /.cmake/Modules/copyright.expat: -------------------------------------------------------------------------------- 1 | This work was packaged for Debian by: 2 | 3 | on 4 | 5 | It was downloaded from 6 | 7 | 8 | 9 | Upstream Author(s): 10 | 11 | 12 | 13 | Copyright: 14 | 15 | Copyright (C) 16 | 17 | License: 18 | 19 | Permission is hereby granted, free of charge, to any person obtaining a copy 20 | of this software and associated documentation files (the "Software"), to deal 21 | in the Software without restriction, including without limitation the rights 22 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 23 | copies of the Software, and to permit persons to whom the Software is 24 | furnished to do so, subject to the following conditions: 25 | 26 | The above copyright notice and this permission notice shall be included in 27 | all copies or substantial portions of the Software. 28 | 29 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 30 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 31 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 32 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 33 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 34 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 35 | THE SOFTWARE. 36 | 37 | The Debian packaging is: 38 | 39 | Copyright (C) 40 | 41 | and is licensed under the GPL version 3, 42 | see `/usr/share/common-licenses/GPL-3'. 43 | 44 | 45 | -------------------------------------------------------------------------------- /.cmake/Modules/uninstall.cmake: -------------------------------------------------------------------------------- 1 | set(MANIFEST "${CMAKE_CURRENT_BINARY_DIR}/install_manifest.txt") 2 | 3 | if(NOT EXISTS ${MANIFEST}) 4 | message(FATAL_ERROR "Cannot find install manifest: '${MANIFEST}'") 5 | endif() 6 | 7 | file(STRINGS ${MANIFEST} files) 8 | foreach(file ${files}) 9 | if(EXISTS ${file}) 10 | message(STATUS "Removing file: '${file}'") 11 | 12 | exec_program( 13 | ${CMAKE_COMMAND} ARGS "-E remove ${file}" 14 | OUTPUT_VARIABLE stdout 15 | RETURN_VALUE result 16 | ) 17 | if(NOT "${result}" STREQUAL 0) 18 | message(FATAL_ERROR "Failed to remove file: '${file}'.") 19 | endif() 20 | else() 21 | MESSAGE(STATUS "File '${file}' does not exist.") 22 | endif() 23 | endforeach(file) 24 | -------------------------------------------------------------------------------- /.cmake/copy-source.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | CURDIR=$(dirname $0) 4 | SOURCE_DIR=$1; shift 5 | DEST_DIR=$1; shift 6 | 7 | ( 8 | cd "$SOURCE_DIR" 9 | mkdir -p "$DEST_DIR" 10 | "$CURDIR/git-archive-all.sh" --format tar -- - | tar -x -C "$DEST_DIR" 11 | ) 12 | -------------------------------------------------------------------------------- /.cmake/git-archive-all.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash - 2 | # 3 | # File: git-archive-all.sh 4 | # 5 | # Description: A utility script that builds an archive file(s) of all 6 | # git repositories and submodules in the current path. 7 | # Useful for creating a single tarfile of a git super- 8 | # project that contains other submodules. 9 | # 10 | # Examples: Use git-archive-all.sh to create archive distributions 11 | # from git repositories. To use, simply do: 12 | # 13 | # cd $GIT_DIR; git-archive-all.sh 14 | # 15 | # where $GIT_DIR is the root of your git superproject. 16 | # 17 | # License: GPL3+ 18 | # 19 | ############################################################################### 20 | # 21 | # This program is free software; you can redistribute it and/or modify 22 | # it under the terms of the GNU General Public License as published by 23 | # the Free Software Foundation; either version 3 of the License, or 24 | # (at your option) any later version. 25 | # 26 | # This program is distributed in the hope that it will be useful, 27 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 28 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 29 | # GNU General Public License for more details. 30 | # 31 | # You should have received a copy of the GNU General Public License 32 | # along with this program; if not, write to the Free Software 33 | # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 34 | # 35 | ############################################################################### 36 | 37 | # DEBUGGING 38 | set -e 39 | set -C # noclobber 40 | 41 | # TRAP SIGNALS 42 | trap 'cleanup' QUIT EXIT 43 | 44 | # For security reasons, explicitly set the internal field separator 45 | # to newline, space, tab 46 | OLD_IFS=$IFS 47 | IFS=' 48 | ' 49 | 50 | function cleanup () { 51 | rm -f $TMPFILE 52 | rm -f $TOARCHIVE 53 | IFS="$OLD_IFS" 54 | } 55 | 56 | function usage () { 57 | echo "Usage is as follows:" 58 | echo 59 | echo "$PROGRAM <--version>" 60 | echo " Prints the program version number on a line by itself and exits." 61 | echo 62 | echo "$PROGRAM <--usage|--help|-?>" 63 | echo " Prints this usage output and exits." 64 | echo 65 | echo "$PROGRAM [--format ] [--prefix ] [--verbose|-v] [--separate|-s]" 66 | echo " [--tree-ish|-t ] [output_file]" 67 | echo " Creates an archive for the entire git superproject, and its submodules" 68 | echo " using the passed parameters, described below." 69 | echo 70 | echo " If '--format' is specified, the archive is created with the named" 71 | echo " git archiver backend. Obviously, this must be a backend that git archive" 72 | echo " understands. The format defaults to 'tar' if not specified." 73 | echo 74 | echo " If '--prefix' is specified, the archive's superproject and all submodules" 75 | echo " are created with the prefix named. The default is to not use one." 76 | echo 77 | echo " If '--separate' or '-s' is specified, individual archives will be created" 78 | echo " for each of the superproject itself and its submodules. The default is to" 79 | echo " concatenate individual archives into one larger archive." 80 | echo 81 | echo " If '--tree-ish' is specified, the archive will be created based on whatever" 82 | echo " you define the tree-ish to be. Branch names, commit hash, etc. are acceptable." 83 | echo " Defaults to HEAD if not specified. See git archive's documentation for more" 84 | echo " information on what a tree-ish is." 85 | echo 86 | echo " If 'output_file' is specified, the resulting archive is created as the" 87 | echo " file named. This parameter is essentially a path that must be writeable." 88 | echo " When combined with '--separate' ('-s') this path must refer to a directory." 89 | echo " Without this parameter or when combined with '--separate' the resulting" 90 | echo " archive(s) are named with a dot-separated path of the archived directory and" 91 | echo " a file extension equal to their format (e.g., 'superdir.submodule1dir.tar')." 92 | echo 93 | echo " The special value '-' (single dash) is treated as STDOUT and, when used, the" 94 | echo " --separate option is ignored. Use a double-dash to separate the outfile from" 95 | echo " the value of previous options. For example, to write a .zip file to STDOUT:" 96 | echo 97 | echo " ./$PROGRAM --format zip -- -" 98 | echo 99 | echo " If '--verbose' or '-v' is specified, progress will be printed." 100 | } 101 | 102 | function version () { 103 | echo "$PROGRAM version $VERSION" 104 | } 105 | 106 | # Internal variables and initializations. 107 | readonly PROGRAM=`basename "$0"` 108 | readonly VERSION=0.3 109 | 110 | SEPARATE=0 111 | VERBOSE=0 112 | 113 | TARCMD=`command -v gnutar || command -v tar` 114 | FORMAT=tar 115 | PREFIX= 116 | TREEISH=HEAD 117 | 118 | # RETURN VALUES/EXIT STATUS CODES 119 | readonly E_BAD_OPTION=254 120 | readonly E_UNKNOWN=255 121 | 122 | # Process command-line arguments. 123 | while test $# -gt 0; do 124 | if [ x"$1" == x"--" ]; then 125 | # detect argument termination 126 | shift 127 | break 128 | fi 129 | case $1 in 130 | --format ) 131 | shift 132 | FORMAT="$1" 133 | shift 134 | ;; 135 | 136 | --prefix ) 137 | shift 138 | PREFIX="$1" 139 | shift 140 | ;; 141 | 142 | --separate | -s ) 143 | shift 144 | SEPARATE=1 145 | ;; 146 | 147 | --tree-ish | -t ) 148 | shift 149 | TREEISH="$1" 150 | shift 151 | ;; 152 | 153 | --version ) 154 | version 155 | exit 156 | ;; 157 | 158 | --verbose | -v ) 159 | shift 160 | VERBOSE=1 161 | ;; 162 | 163 | -? | --usage | --help ) 164 | usage 165 | exit 166 | ;; 167 | 168 | -* ) 169 | echo "Unrecognized option: $1" >&2 170 | usage 171 | exit $E_BAD_OPTION 172 | ;; 173 | 174 | * ) 175 | break 176 | ;; 177 | esac 178 | done 179 | 180 | OLD_PWD="`pwd`" 181 | TMPDIR=${TMPDIR:-/tmp} 182 | TMPFILE=`mktemp "$TMPDIR/$PROGRAM.XXXXXX"` # Create a place to store our work's progress 183 | TOARCHIVE=`mktemp "$TMPDIR/$PROGRAM.toarchive.XXXXXX"` 184 | OUT_FILE=$OLD_PWD # assume "this directory" without a name change by default 185 | 186 | if [ ! -z "$1" ]; then 187 | OUT_FILE="$1" 188 | if [ "-" == $OUT_FILE ]; then 189 | SEPARATE=0 190 | fi 191 | shift 192 | fi 193 | 194 | # Validate parameters; error early, error often. 195 | if [ "-" == $OUT_FILE -o $SEPARATE -ne 1 ] && [ "$FORMAT" == "tar" -a `$TARCMD --help | grep -q -- "--concatenate"; echo $?` -ne 0 ]; then 196 | echo "Your 'tar' does not support the '--concatenate' option, which we need" 197 | echo "to produce a single tarfile. Either install a compatible tar (such as" 198 | echo "gnutar), or invoke $PROGRAM with the '--separate' option." 199 | exit 200 | elif [ $SEPARATE -eq 1 -a ! -d $OUT_FILE ]; then 201 | echo "When creating multiple archives, your destination must be a directory." 202 | echo "If it's not, you risk being surprised when your files are overwritten." 203 | exit 204 | elif [ `git config -l | grep -q '^core\.bare=false'; echo $?` -ne 0 ]; then 205 | echo "$PROGRAM must be run from a git working copy (i.e., not a bare repository)." 206 | exit 207 | fi 208 | 209 | # Create the superproject's git-archive 210 | if [ $VERBOSE -eq 1 ]; then 211 | echo -n "creating superproject archive..." 212 | fi 213 | git archive --format=$FORMAT --prefix="$PREFIX" $TREEISH > $TMPDIR/$(basename "$(pwd)").$FORMAT 214 | if [ $VERBOSE -eq 1 ]; then 215 | echo "done" 216 | fi 217 | echo $TMPDIR/$(basename "$(pwd)").$FORMAT >| $TMPFILE # clobber on purpose 218 | superfile=`head -n 1 $TMPFILE` 219 | 220 | if [ $VERBOSE -eq 1 ]; then 221 | echo -n "looking for subprojects..." 222 | fi 223 | # find all '.git' dirs, these show us the remaining to-be-archived dirs 224 | # we only want directories that are below the current directory 225 | find . -mindepth 2 -name '.git' -type d -print | sed -e 's/^\.\///' -e 's/\.git$//' >> $TOARCHIVE 226 | # as of version 1.7.8, git places the submodule .git directories under the superprojects .git dir 227 | # the submodules get a .git file that points to their .git dir. we need to find all of these too 228 | find . -mindepth 2 -name '.git' -type f -print | xargs grep -l "gitdir" | sed -e 's/^\.\///' -e 's/\.git$//' >> $TOARCHIVE 229 | if [ $VERBOSE -eq 1 ]; then 230 | echo "done" 231 | echo " found:" 232 | cat $TOARCHIVE | while read arch 233 | do 234 | echo " $arch" 235 | done 236 | fi 237 | 238 | if [ $VERBOSE -eq 1 ]; then 239 | echo -n "archiving submodules..." 240 | fi 241 | while read path; do 242 | TREEISH=$(git submodule | grep "^ .*${path%/} " | cut -d ' ' -f 2) # git submodule does not list trailing slashes in $path 243 | cd "$path" 244 | git archive --format=$FORMAT --prefix="${PREFIX}$path" ${TREEISH:-HEAD} > "$TMPDIR"/"$(echo "$path" | sed -e 's/\//./g')"$FORMAT 245 | if [ $FORMAT == 'zip' ]; then 246 | # delete the empty directory entry; zipped submodules won't unzip if we don't do this 247 | zip -d "$(tail -n 1 $TMPFILE)" "${PREFIX}${path%/}" >/dev/null # remove trailing '/' 248 | fi 249 | echo "$TMPDIR"/"$(echo "$path" | sed -e 's/\//./g')"$FORMAT >> $TMPFILE 250 | cd "$OLD_PWD" 251 | done < $TOARCHIVE 252 | if [ $VERBOSE -eq 1 ]; then 253 | echo "done" 254 | fi 255 | 256 | if [ $VERBOSE -eq 1 ]; then 257 | echo -n "concatenating archives into single archive..." 258 | fi 259 | # Concatenate archives into a super-archive. 260 | if [ $SEPARATE -eq 0 -o "-" == $OUT_FILE ]; then 261 | if [ $FORMAT == 'tar.gz' ]; then 262 | gunzip $superfile 263 | superfile=${superfile:0: -3} # Remove '.gz' 264 | sed -e '1d' $TMPFILE | while read file; do 265 | gunzip $file 266 | file=${file:0: -3} 267 | $TARCMD --concatenate -f "$superfile" "$file" && rm -f "$file" 268 | done 269 | gzip $superfile 270 | superfile=$superfile.gz 271 | elif [ $FORMAT == 'tar' ]; then 272 | sed -e '1d' $TMPFILE | while read file; do 273 | $TARCMD --concatenate -f "$superfile" "$file" && rm -f "$file" 274 | done 275 | elif [ $FORMAT == 'zip' ]; then 276 | sed -e '1d' $TMPFILE | while read file; do 277 | # zip incorrectly stores the full path, so cd and then grow 278 | cd `dirname "$file"` 279 | zip -g "$superfile" `basename "$file"` && rm -f "$file" 280 | done 281 | cd "$OLD_PWD" 282 | fi 283 | 284 | echo "$superfile" >| $TMPFILE # clobber on purpose 285 | fi 286 | if [ $VERBOSE -eq 1 ]; then 287 | echo "done" 288 | fi 289 | 290 | if [ $VERBOSE -eq 1 ]; then 291 | echo -n "moving archive to $OUT_FILE..." 292 | fi 293 | while read file; do 294 | if [ "-" == $OUT_FILE ]; then 295 | cat "$file" && rm -f "$file" 296 | else 297 | mv "$file" "$OUT_FILE" 298 | fi 299 | done < $TMPFILE 300 | if [ $VERBOSE -eq 1 ]; then 301 | echo "done" 302 | fi 303 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !*/ 3 | 4 | !.gitignore 5 | 6 | !*.c 7 | !*.h 8 | !*.h.in 9 | 10 | !LICENSE 11 | !HEADER 12 | !README.md 13 | !INSTALL.md 14 | !ChangeLog 15 | !doc/* 16 | 17 | !CMakeLists.txt 18 | 19 | build/* 20 | include/csptr/config.h 21 | *~ 22 | *.swp 23 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: c 2 | compiler: 3 | - gcc 4 | sudo: false 5 | addons: 6 | apt: 7 | packages: 8 | - check 9 | before_install: 10 | - pip install --user cpp-coveralls 11 | - export CFLAGS="-g -O0" 12 | script: 13 | - mkdir -p build && cd $_ && cmake ${FEATURES} -DCOVERALLS=ON -DCMAKE_BUILD_TYPE=Debug 14 | .. && make && make test 15 | after_success: 16 | - make coveralls 17 | after_failure: 18 | - cat $(find check -iname '*.log') /dev/null 19 | env: 20 | matrix: 21 | - FEATURES="" 22 | - FEATURES="-DFIXED_ALLOCATOR=ON" 23 | - FEATURES="-DSENTINEL=OFF" 24 | - FEATURES="-DSENTINEL=OFF -DFIXED_ALLOCATOR=ON" 25 | global: 26 | secure: CQ+DjIdSOn5kQALHcTJ1whkZDLVmTDbPLV3g8Es0Gz4/goFfgGWMyF4VuKD+UD+O0Z7eV/epZMQfatbG7jIMXQTai7ylXu0hyHA0rE7ypalWBRyRZC9raTChrlonLv9QqucNrcFepIDcAaSsX2bJYH0KBsqasdgGJmjPlo/1CLs= 27 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 2.8) 2 | 3 | project(csptr C) 4 | 5 | # Project setup & environment variables 6 | 7 | enable_testing() 8 | 9 | set(PROJECT_VERSION "2.0.5-7") 10 | set(MODULE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/.cmake/Modules") 11 | set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${MODULE_DIR}) 12 | 13 | if (NOT MSVC) 14 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Werror -g -std=gnu99 -Wno-unused-result -Wno-missing-field-initializers") 15 | endif () 16 | 17 | if (WIN32 AND NOT MSVC) 18 | set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,-no-undefined") 19 | endif() 20 | 21 | # Setup coveralls 22 | 23 | option(COVERALLS "Turn on coveralls support" OFF) 24 | option(COVERALLS_UPLOAD "Upload the generated coveralls json" ON) 25 | 26 | if (COVERALLS AND NOT LIBCSPTR_DISABLE_COVERALLS) 27 | include(Coveralls) 28 | coveralls_turn_on_coverage() 29 | endif() 30 | 31 | # Find dependencies 32 | 33 | option(LIBCSPTR_TESTS "Turn on tests" ON) 34 | 35 | find_package(Check) 36 | if (CHECK_FOUND AND LIBCSPTR_TESTS AND NOT LIBCSPTR_DISABLE_TESTS) 37 | add_subdirectory(check) 38 | endif() 39 | 40 | # Setup options 41 | 42 | option(SENTINEL "Use a sentinel for the variadic function arguments" ON) 43 | option(FIXED_ALLOCATOR "Define if malloc should always be used" OFF) 44 | 45 | # Generate the configure file 46 | 47 | configure_file( 48 | "${CMAKE_CURRENT_SOURCE_DIR}/src/config.h.in" 49 | "${CMAKE_CURRENT_SOURCE_DIR}/include/csptr/config.h" 50 | ) 51 | 52 | # List sources and headers 53 | 54 | set(SOURCE_FILES 55 | src/array.c 56 | src/mman.c 57 | src/mman.h 58 | ) 59 | 60 | set(INTERFACE_FILES 61 | include/csptr/config.h 62 | include/csptr/smalloc.h 63 | include/csptr/array.h 64 | include/csptr/smart_ptr.h 65 | include/csptr/common.h 66 | ) 67 | 68 | set(MAN_FILES doc/csptr.3) 69 | 70 | if (NOT WIN32) 71 | add_definitions("-fPIC") 72 | endif () 73 | 74 | include_directories(include/csptr src) 75 | add_library(csptr STATIC ${SOURCE_FILES} ${INTERFACE_FILES}) 76 | 77 | if (COVERALLS AND NOT LIBCSPTR_DISABLE_COVERALLS) 78 | coveralls_setup("${SOURCE_FILES}" ${COVERALLS_UPLOAD}) 79 | endif() 80 | 81 | install(FILES ${INTERFACE_FILES} DESTINATION include/csptr) 82 | install(FILES ${MAN_FILES} DESTINATION share/man/man3) 83 | install(TARGETS csptr 84 | RUNTIME DESTINATION bin 85 | LIBRARY DESTINATION lib 86 | ARCHIVE DESTINATION lib 87 | ) 88 | 89 | add_custom_target(uninstall 90 | "${CMAKE_COMMAND}" -P "${CMAKE_MODULE_PATH}/uninstall.cmake" 91 | ) 92 | 93 | include (PackageConfig) 94 | 95 | option(UPLOAD_DEB "Upload package to launchpad" OFF) 96 | 97 | if (UNIX AND UPLOAD_DEB) 98 | include (DebConfig) 99 | endif () 100 | 101 | -------------------------------------------------------------------------------- /ChangeLog: -------------------------------------------------------------------------------- 1 | 2015-03-18 Franklin "Snaipe" Mathieu 2 | 3 | * include/csptr/{smart_ptr.h,apply.h}: Removed the destructor helper macro 4 | * include/csptr/{smart_ptr.h,smalloc.h}: Changed the vararg usage to 5 | struct vararg. This change is **NOT** backward-compatible. Parenthesis 6 | around the value were removed with this change, and metadata is no longer 7 | passed as two separate parameters. 8 | 9 | 2015-01-26 Franklin "Snaipe" Mathieu 10 | 11 | * include/csptr/smart_ptr.h: Smart pointers now take a mandatory value. 12 | * doc/csptr.3: Fixed some typos and updated to latest interface. 13 | 14 | 2015-01-20 Franklin "Snaipe" Mathieu 15 | 16 | * configure.ac: Removed --with-malloc-wrapper ./configure flag. 17 | * src/wrap_malloc.{c,h}: Removed malloc/free wrappers. 18 | * check/*: Added unit tests & coverage reports. 19 | * mman.c: Fix for shared pointers accessing the wrong metadata. 20 | 21 | 2015-01-14 Franklin "Snaipe" Mathieu 22 | 23 | * configure.ac: Added --with-malloc-wrapper and --with-fixed-allocator 24 | flags for ./configure. 25 | 26 | * src/mman.c: Added a fixed allocator support -- if the user does not 27 | want to override at runtime the allocators used by smalloc/sfree and just 28 | want to use malloc and free, they may enable this option using the 29 | --with-fixed-allocator configuration flag. 30 | 31 | * src/wrap_malloc.{c,h}, src/mman.c: Added malloc/free wrappers. 32 | Pointers produced by malloc can be used with the `smart` attribute, 33 | and smart pointers may be passed to free. This option is deactivated 34 | by default, and can be enabled using the --with-malloc-wrapper 35 | configuration flag. 36 | 37 | 2015-01-14 Franklin "Snaipe" Mathieu 38 | 39 | * src/smart_ptr.h: unique_ptr and shared_ptr now take a type parameter 40 | instead of a size. 41 | 42 | * src/smart_ptr.h: Added support for static array types in the unique_ptr 43 | and shared_ptr macros. 44 | 45 | * src/mman.{c,h}: Added smart array allocation through smalloc. smalloc 46 | has been changed to take a mandatory `nmemb` parameter, that may be 0 47 | if the allocated type is a scalar, and an array for any other value. 48 | 49 | 2015-01-13 Franklin "Snaipe" Mathieu 50 | 51 | * src/smart_ptr.h: Added unique_ptr and shared_ptr macros, added 52 | `smart` variable attribute. 53 | 54 | * src/mman.{c,h}: Added smalloc, sfree, sref, and get_smart_user_meta. 55 | Alternative allocators may be specified by setting the contents of 56 | `smalloc_allocator`. 57 | -------------------------------------------------------------------------------- /HEADER: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright © 2015-2016 Franklin "Snaipe" Mathieu 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | -------------------------------------------------------------------------------- /INSTALL.md: -------------------------------------------------------------------------------- 1 | # Compilation & installation instructions 2 | 3 | ## CMake options 4 | 5 | ### Developer options 6 | 7 | These options are useful for developers that want to customize libcsptr. 8 | 9 | * `-DSENTINEL=`: Use a sentinel for the variadic function parameters. 10 | This must be left on for maximum compatibility. However, in case you target 11 | embedded systems *and* your C compiler supports empty compound literals as 12 | a nonstandard extension, you may want to turn it off. 13 | This option is **ON** by default. 14 | * `-DFIXED_ALLOCATOR=`: If turned on, directly use malloc/free as the 15 | memory allocator, and ignore any allocator provided by `smalloc_allocator`. 16 | This option is **OFF** by default. 17 | 18 | ### Maintainer options 19 | 20 | These options target maintainers of libcsptr, and are not otherwise useful. 21 | 22 | * `-DLIBCSPTR_TESTS=`: Compiles tests alongside libcsptr. 23 | This option is **ON** by default. 24 | * `-DCOVERALLS=`: Turns on coverage for libcsptr. 25 | This option is **OFF** by default. 26 | * `-DCOVERALLS_UPLOAD=`: Uploads coverage for libcsptr to coveralls. 27 | The option is only relevant if `-DCOVERALLS=ON` is specified. 28 | This option is **ON** by default. 29 | 30 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright © 2015-2016 Franklin "Snaipe" Mathieu 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | C Smart Pointers 2 | ================ 3 | 4 | [![Build Status](https://travis-ci.org/Snaipe/libcsptr.svg?branch=master)](https://travis-ci.org/Snaipe/libcsptr) 5 | [![Coverage Status](https://coveralls.io/repos/Snaipe/libcsptr/badge.svg?branch=master)](https://coveralls.io/r/Snaipe/libcsptr?branch=master) 6 | [![License](https://img.shields.io/badge/license-MIT-blue.svg?style=flat)](https://github.com/Snaipe/libcsptr/blob/master/LICENSE) 7 | [![Version](https://img.shields.io/github/tag/Snaipe/libcsptr.svg?label=version&style=flat)](https://github.com/Snaipe/libcsptr/releases) 8 | 9 | ## What this is 10 | 11 | This project is an attempt to bring smart pointer constructs 12 | to the (GNU) C programming language. 13 | 14 | ### Features 15 | 16 | * `unique_ptr`, `shared_ptr` macros, and `smart` type attribute 17 | * Destructor support for cleanup 18 | * Custom variable metadata on allocation 19 | * Cross-platform: tested under linux 3.18.6-1, Mac OS X Yosemite 10.10, and Windows 7 (with MinGW and the Cygwin port of GCC) 20 | 21 | ## Installing 22 | 23 | ### With a package manager 24 | 25 | * Mac OS X: `brew install snaipe/soft/libcsptr` 26 | * [AUR](https://aur.archlinux.org/packages/libcsptr-git/): `yaourt -S libcsptr` 27 | * Ubuntu: 28 | 29 | ```bash 30 | $ sudo add-apt-repository ppa:snaipewastaken/ppa 31 | $ sudo apt-get update 32 | $ sudo apt-get install libcsptr-dev 33 | ``` 34 | 35 | ### Building from source 36 | #### Prerequisites 37 | 38 | To compile the library, GCC 4.6+ is needed. 39 | 40 | #### Installation 41 | 42 | 1. Clone this repository 43 | 2. run `mkdir build && cd $_ && cmake -DCMAKE_INSTALL_PREFIX=$HOME .. && make && make install` 44 | from the project root for a local install, or run 45 | `mkdir build && cd $_ && cmake -DCMAKE_INSTALL_PREFIX=/usr .. && make && sudo make install` for a global install. 46 | 47 | ## Examples 48 | 49 | * Simple unique\_ptr: 50 | simple1.c: 51 | ```c 52 | #include 53 | #include 54 | 55 | int main(void) { 56 | // some_int is an unique_ptr to an int with a value of 1. 57 | smart int *some_int = unique_ptr(int, 1); 58 | 59 | printf("%p = %d\n", some_int, *some_int); 60 | 61 | // some_int is destroyed here 62 | return 0; 63 | } 64 | ``` 65 | Shell session: 66 | ```bash 67 | $ gcc -std=c99 -o simple1 simple1.c -lcsptr 68 | $ valgrind ./simple1 69 | ==3407== Memcheck, a memory error detector 70 | ==3407== Copyright (C) 2002-2013, and GNU GPL\'d, by Julian Seward et al. 71 | ==3407== Using Valgrind-3.10.0 and LibVEX; rerun with -h for copyright info 72 | ==3407== Command: ./test1 73 | ==3407== 74 | 0x53db068 = 1 75 | ==3407== 76 | ==3407== HEAP SUMMARY: 77 | ==3407== in use at exit: 0 bytes in 0 blocks 78 | ==3407== total heap usage: 1 allocs, 1 frees, 48 bytes allocated 79 | ==3407== 80 | ==3407== All heap blocks were freed -- no leaks are possible 81 | ==3407== 82 | ==3407== For counts of detected and suppressed errors, rerun with: -v 83 | ==3407== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0) 84 | ``` 85 | * Simple unique\_ptr with destructor: 86 | ```c 87 | #include 88 | #include 89 | #include 90 | 91 | struct log_file { 92 | int fd; 93 | // ... 94 | }; 95 | 96 | void cleanup_log_file(void *ptr, void *meta) { 97 | (void) meta; 98 | close(((struct log_file *) ptr)->fd); 99 | } 100 | 101 | int main(void) { 102 | smart struct log_file *log = unique_ptr(struct log_file, { 103 | .fd = open("/dev/null", O_WRONLY | O_APPEND), 104 | // ... 105 | }, cleanup_log_file); 106 | 107 | write(log->fd, "Hello", 5); 108 | 109 | // cleanup_log_file is called, then log is freed 110 | return 0; 111 | } 112 | ``` 113 | * Allocating a smart array and printing its contents before destruction: 114 | ```c 115 | #include 116 | #include 117 | #include 118 | 119 | void print_int(void *ptr, void *meta) { 120 | (void) meta; 121 | // ptr points to the current element 122 | // meta points to the array metadata (global to the array), if any. 123 | printf("%d\n", *(int*) ptr); 124 | } 125 | 126 | int main(void) { 127 | // Destructors for array types are run on every element of the 128 | // array before destruction. 129 | smart int *ints = unique_ptr(int[5], {5, 4, 3, 2, 1}, print_int); 130 | // ints == {5, 4, 3, 2, 1} 131 | 132 | // Smart arrays are length-aware 133 | for (size_t i = 0; i < array_length(ints); ++i) { 134 | ints[i] = i + 1; 135 | } 136 | // ints == {1, 2, 3, 4, 5} 137 | 138 | return 0; 139 | } 140 | ``` 141 | 142 | ## More examples 143 | 144 | * Using a different memory allocator (although most will replace malloc/free): 145 | ```c 146 | #include 147 | 148 | void *some_allocator(size_t); 149 | void some_deallocator(void *); 150 | 151 | int main(void) { 152 | smalloc_allocator = (s_allocator) {some_allocator, some_deallocator}; 153 | // ... 154 | return 0; 155 | } 156 | ``` 157 | 158 | * Automatic cleanup on error cases: 159 | ```c 160 | #include 161 | #include 162 | #include 163 | 164 | struct log_file { 165 | int fd; 166 | // ... 167 | }; 168 | 169 | static void close_log(void *ptr, void *meta) { 170 | (void) meta; 171 | struct log_file *log = ptr; 172 | if (log->fd != -1) 173 | close(log->fd); 174 | } 175 | 176 | struct log_file *open_log(const char *path) { 177 | smart struct log_file *log = shared_ptr(struct log_file, {0}, close_log); 178 | if (!log) // failure to allocate 179 | return NULL; // nothing happens, destructor is not called 180 | 181 | log->fd = open(path, O_WRONLY | O_APPEND | O_CREAT, 0644); 182 | if (log->fd == -1) // failure to open 183 | return NULL; // log gets destroyed, file descriptor is not closed since fd == -1. 184 | 185 | return sref(log); // a new reference on log is returned, it does not get destoyed 186 | } 187 | 188 | int main(void) { 189 | smart struct log_file *log = open_log("/dev/null"); 190 | // ... 191 | return 0; // file descriptor is closed, log is freed 192 | } 193 | ``` 194 | * Using named parameters: 195 | ```c 196 | #include 197 | 198 | void nothing(void *ptr, void *meta) {} 199 | 200 | int main(void) { 201 | struct { int a; } m = { 1 }; 202 | 203 | smart int *i = unique_ptr(int, 204 | .dtor = nothing, 205 | .value = 42, 206 | .meta = { &m, sizeof (m) } 207 | ); 208 | 209 | return 0; 210 | } 211 | ``` 212 | 213 | ## FAQ 214 | 215 | **Q. Why didn't you use C++ you moron ?** 216 | A. Because when I first started this, I was working on a C project. 217 | Also, because it's fun. 218 | 219 | **Q. Can I use this on a serious project ?** 220 | A. Yes, but as this project has not been widely used, there might be 221 | some bugs. Beware! 222 | 223 | **Q. How did you make this ?** 224 | A. Here's a [link to my blog post](http://snaipe.me/c/c-smart-pointers/) on the matter. 225 | -------------------------------------------------------------------------------- /check/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | include_directories(../include) 2 | 3 | if (NOT MSVC AND "${CMAKE_C_COMPILER_ID}" STREQUAL "GNU") 4 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-trampolines") 5 | endif () 6 | 7 | set(TEST_SOURCES 8 | test/test.c 9 | test/test.h 10 | test/utils.h 11 | test/scalar.c 12 | test/misc.c 13 | test/shared.c 14 | test/array.c 15 | ) 16 | 17 | add_executable(check_unit ${TEST_SOURCES}) 18 | target_link_libraries(check_unit ${CHECK_LIBRARIES} csptr) 19 | 20 | add_test(check_unit check_unit) 21 | -------------------------------------------------------------------------------- /check/test/array.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "csptr/array.h" 3 | #include "utils.h" 4 | 5 | #define ARRAY_SIZE 25 6 | 7 | __attribute__((always_inline)) 8 | inline void assert_valid_array(void *ptr, size_t len, size_t size) { 9 | assert_valid_ptr(ptr); 10 | ck_assert_msg(array_length(ptr) == len, 11 | "Mismatching array lengths."); 12 | ck_assert_msg(array_type_size(ptr) == size, 13 | "Mismatching compound type sizes."); 14 | } 15 | 16 | START_TEST (test_array) { 17 | smart int *arr = unique_ptr(int[ARRAY_SIZE], {}); 18 | assert_valid_array(arr, ARRAY_SIZE, sizeof (int)); 19 | } END_TEST 20 | 21 | START_TEST (test_array_dtor_run) { 22 | int dtor_run = 0; 23 | int *arr; 24 | f_destructor dtor = lambda(void, (void *ptr, UNUSED void *meta) { 25 | ck_assert(ptr == arr + dtor_run); 26 | dtor_run++; 27 | }); 28 | 29 | arr = unique_ptr(int[ARRAY_SIZE], {}, dtor); 30 | assert_valid_array(arr, ARRAY_SIZE, sizeof (int)); 31 | 32 | sfree(arr); 33 | ck_assert_msg(dtor_run == ARRAY_SIZE, "Expected destructor to run"); 34 | } END_TEST 35 | 36 | START_TEST (test_array_meta) { 37 | smart int *arr = unique_ptr(int[ARRAY_SIZE], {}, .meta = { &m, sizeof (m) }); 38 | assert_valid_array(arr, ARRAY_SIZE, sizeof (int)); 39 | assert_valid_meta(&m, array_user_meta(arr)); 40 | } END_TEST 41 | 42 | START_TEST (test_array_dtor_run_with_meta) { 43 | int dtor_run = 0; 44 | f_destructor dtor = lambda(void, (UNUSED void *ptr, UNUSED void *meta) { dtor_run = 1; }); 45 | 46 | int *arr = unique_ptr(int[ARRAY_SIZE], {}, dtor, { &m, sizeof (m) }); 47 | assert_valid_array(arr, ARRAY_SIZE, sizeof (int)); 48 | assert_valid_meta(&m, array_user_meta(arr)); 49 | 50 | sfree(arr); 51 | ck_assert_msg(dtor_run, "Expected destructor to run"); 52 | } END_TEST 53 | 54 | TCase *make_array_tests(void) { 55 | TCase *tc = tcase_create("array"); 56 | tcase_add_test(tc, test_array); 57 | tcase_add_test(tc, test_array_meta); 58 | tcase_add_test(tc, test_array_dtor_run); 59 | tcase_add_test(tc, test_array_dtor_run_with_meta); 60 | return tc; 61 | } 62 | -------------------------------------------------------------------------------- /check/test/misc.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "csptr/smart_ptr.h" 3 | #include "csptr/config.h" 4 | #include "utils.h" 5 | 6 | START_TEST (test_zero_size) { 7 | void *ptr = smalloc(0, 0, UNIQUE); 8 | ck_assert_msg(ptr == NULL, "Expected NULL pointer to be returned."); 9 | } END_TEST 10 | 11 | #ifndef SMALLOC_FIXED_ALLOCATOR 12 | START_TEST (test_alloc_failure) { 13 | smalloc_allocator = (s_allocator) { 14 | lambda(void *, (UNUSED size_t s) { return NULL; }), 15 | lambda(void, (UNUSED void *ptr) {}) 16 | }; 17 | smart void *ptr = unique_ptr(int, 42); 18 | ck_assert_msg(ptr == NULL, "Expected NULL pointer to be returned."); 19 | smalloc_allocator = (s_allocator) {malloc, free}; 20 | } END_TEST 21 | #endif 22 | 23 | TCase *make_misc_tests(void) { 24 | TCase *tc = tcase_create("misc"); 25 | #ifndef SMALLOC_FIXED_ALLOCATOR 26 | tcase_add_test(tc, test_alloc_failure); 27 | #endif 28 | tcase_add_test(tc, test_zero_size); 29 | return tc; 30 | } 31 | -------------------------------------------------------------------------------- /check/test/scalar.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "csptr/smart_ptr.h" 3 | #include "utils.h" 4 | 5 | START_TEST (test_pointer_valid) { 6 | smart int *a = unique_ptr(int, 42); 7 | assert_valid_ptr(a); 8 | ck_assert_msg(get_smart_ptr_meta(a) == NULL, "Expected pointer to have no metadata"); 9 | } END_TEST 10 | 11 | START_TEST (test_dtor_run) { 12 | int dtor_run = 0; 13 | f_destructor dtor = lambda(void, (UNUSED void *ptr, UNUSED void *meta) { dtor_run = 1; }); 14 | int *a = unique_ptr(int, 42, dtor); 15 | assert_valid_ptr(a); 16 | ck_assert_msg(get_smart_ptr_meta(a) == NULL, "Expected pointer to have no metadata"); 17 | sfree(a); 18 | ck_assert_msg(dtor_run, "Expected destructor to run"); 19 | } END_TEST 20 | 21 | START_TEST (test_meta) { 22 | smart int *a = unique_ptr(int, 42, .meta = { &m, sizeof (m) }); 23 | assert_valid_ptr(a); 24 | assert_valid_meta(&m, get_smart_ptr_meta(a)); 25 | } END_TEST 26 | 27 | START_TEST (test_dtor_run_with_meta) { 28 | int dtor_run = 0; 29 | 30 | f_destructor dtor = lambda(void, (UNUSED void *ptr, UNUSED void *meta) { dtor_run = 1; }); 31 | int *a = unique_ptr(int, 42, dtor, { &m, sizeof (m) }); 32 | assert_valid_ptr(a); 33 | assert_valid_meta(&m, get_smart_ptr_meta(a)); 34 | 35 | sfree(a); 36 | ck_assert_msg(dtor_run, "Expected destructor to run"); 37 | } END_TEST 38 | 39 | TCase *make_scalar_tests(void) { 40 | TCase *tc = tcase_create("scalar"); 41 | tcase_add_test(tc, test_pointer_valid); 42 | tcase_add_test(tc, test_meta); 43 | tcase_add_test(tc, test_dtor_run); 44 | tcase_add_test(tc, test_dtor_run_with_meta); 45 | return tc; 46 | } 47 | -------------------------------------------------------------------------------- /check/test/shared.c: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include "csptr/smart_ptr.h" 4 | #include "utils.h" 5 | 6 | START_TEST (test_shared_init) { 7 | smart void *ptr = shared_ptr(int, 42); 8 | assert_valid_ptr(ptr); 9 | } END_TEST 10 | 11 | START_TEST (test_shared_sref) { 12 | int dtor_run = 0; 13 | f_destructor dtor = lambda(void, (UNUSED void *ptr, UNUSED void *meta) { dtor_run = 1; }); 14 | smart void *ptr = shared_ptr(int, 42, dtor); 15 | assert_valid_ptr(ptr); 16 | 17 | { 18 | smart void *ptr2 = sref(ptr); 19 | ck_assert_msg(ptr == ptr2, "Expected reference to be the same pointer."); 20 | } 21 | ck_assert_msg(dtor_run == 0, "Expected destructor NOT to have run."); 22 | } END_TEST 23 | 24 | TCase *make_shared_tests(void) { 25 | TCase *tc = tcase_create("shared"); 26 | tcase_add_test(tc, test_shared_init); 27 | tcase_add_test(tc, test_shared_sref); 28 | return tc; 29 | } 30 | -------------------------------------------------------------------------------- /check/test/test.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "csptr/smart_ptr.h" 4 | 5 | #include "test.h" 6 | #include "utils.h" 7 | 8 | const struct meta m = {1, 2, 3}; 9 | 10 | Suite *master_suite(void) { 11 | Suite *s = suite_create("master"); 12 | suite_add_tcase(s, make_misc_tests()); 13 | suite_add_tcase(s, make_scalar_tests()); 14 | suite_add_tcase(s, make_array_tests()); 15 | suite_add_tcase(s, make_shared_tests()); 16 | return s; 17 | } 18 | 19 | int main(void) { 20 | SRunner *sr = srunner_create(master_suite()); 21 | 22 | srunner_run_all(sr, CK_NORMAL); 23 | int number_failed = srunner_ntests_failed(sr); 24 | srunner_free(sr); 25 | return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE; 26 | } 27 | -------------------------------------------------------------------------------- /check/test/test.h: -------------------------------------------------------------------------------- 1 | #ifndef TEST_H_ 2 | # define TEST_H_ 3 | 4 | #include 5 | 6 | Suite *unique_ptr_suite(void); 7 | 8 | TCase *make_scalar_tests(void); 9 | TCase *make_array_tests(void); 10 | TCase *make_misc_tests(void); 11 | TCase *make_shared_tests(void); 12 | 13 | #endif /* !TEST_H_ */ 14 | -------------------------------------------------------------------------------- /check/test/utils.h: -------------------------------------------------------------------------------- 1 | #ifndef UTILS_H_ 2 | # define UTILS_H_ 3 | 4 | #include 5 | #include 6 | 7 | __attribute__((always_inline)) 8 | inline int is_aligned(void *ptr) { 9 | uintptr_t off = (uintptr_t) ptr; 10 | return !(off % sizeof (void *)); 11 | } 12 | 13 | __attribute__((always_inline)) 14 | inline void assert_valid_ptr(void *ptr) { 15 | ck_assert_msg(ptr != NULL, 16 | "Expected unique_ptr to return a non-null pointer."); 17 | 18 | ck_assert_msg(is_aligned(ptr), 19 | "Expected unique_ptr to return an aligned pointer."); 20 | } 21 | 22 | struct meta { 23 | int i; 24 | long l; 25 | double d; 26 | }; 27 | 28 | extern const struct meta m; 29 | 30 | __attribute__((always_inline)) 31 | inline void assert_valid_meta(const struct meta *m, const struct meta *m2) { 32 | ck_assert_msg(m2 != NULL, "Expected metadata to be present"); 33 | ck_assert_msg(m != m2, "Expected metadata to be copied"); 34 | const int intact = m->i == m2->i 35 | && m->l == m2->l 36 | && m->d == m2->d; 37 | ck_assert_msg(intact, "Expected metadata to be intact."); 38 | } 39 | 40 | #define lambda(RType, Body) ({ RType __fn__ Body; __fn__; }) 41 | #define UNUSED __attribute__ ((unused)) 42 | 43 | #endif /* !UTILS_H_ */ 44 | -------------------------------------------------------------------------------- /debian.copyright: -------------------------------------------------------------------------------- 1 | Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ 2 | Upstream-Name: libcsptr 3 | Upstream-Contact: Franklin "Snaipe" Mathieu 4 | Source: http://github.com/Snaipe/libcsptr 5 | 6 | Files: * 7 | Copyright: 2015, Franklin "Snaipe" Mathieu 8 | License: MIT 9 | Permission is hereby granted, free of charge, to any person obtaining a copy 10 | of this software and associated documentation files (the "Software"), to deal 11 | in the Software without restriction, including without limitation the rights 12 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | copies of the Software, and to permit persons to whom the Software is 14 | furnished to do so, subject to the following conditions: 15 | . 16 | The above copyright notice and this permission notice shall be included in 17 | all copies or substantial portions of the Software. 18 | . 19 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | THE SOFTWARE. 26 | -------------------------------------------------------------------------------- /description.txt: -------------------------------------------------------------------------------- 1 | Libcsptr (for "lib-c-smart-pointers") is a library providing 2 | smart pointers for the (GNU) C programming language. 3 | -------------------------------------------------------------------------------- /doc/csptr.3: -------------------------------------------------------------------------------- 1 | .TH CSPTR 3 2015-03-18 "" "" 2 | .SH NAME 3 | csptr \- smart pointers for the C programming language 4 | .SH SYNOPSIS 5 | .nf 6 | .B #include 7 | .sp 8 | .BI "void *unique_ptr(" "Type" ", " "Value" ", ... );" 9 | .BI "void *shared_ptr(" "Type" ", " "Value" ", ... );" 10 | .sp 11 | .B #include 12 | .B #include 13 | .BI "void *smalloc(size_t " "size" ", size_t " "nmemb" ", int " "kind"); 14 | .BI "void *smalloc(size_t " "size" ", size_t " "nmemb" ", int " "kind" ", void (" "*dtor" ")(void *, void *));" 15 | .BI "void *smalloc(size_t " "size" ", size_t " "nmemb" ", int " "kind" ", void (" "*dtor" ")(void *, void *), struct { void *, size_t } " "meta" ); 16 | .BI "void sfree(void " "*ptr" ); 17 | .BI "void *sref(void " "*ptr" ); 18 | .fi 19 | .SH DESCRIPTION 20 | .PP 21 | The 22 | .BR smalloc () 23 | function calls an allocator 24 | .BR "" ( malloc (3) 25 | by default), such that the returned pointer is a smart pointer. 26 | .IR "The memory is not initialized" , 27 | and great care should be taken to initialize it before destruction if a 28 | destructor has been specified. If 29 | .I size 30 | is 0, then 31 | .BR smalloc () 32 | returns NULL. 33 | If 34 | .I nmemb 35 | is 0, then smalloc shall return a smart pointer to a memory block of at least 36 | .I size 37 | bytes, and the smart pointer is a scalar. Otherwise, it shall return a memory 38 | block to at least 39 | .I size * nmemb 40 | bytes, and the smart pointer is an array. 41 | .PP 42 | The 43 | .BR sfree () 44 | function calls the deallocator associated to the 45 | .BR smalloc () 46 | allocator 47 | .BR "" ( free (3) 48 | by default) on 49 | .I ptr 50 | if the smart pointer is either unique or shared with a reference 51 | count of 0. If the smart pointer is shared, it shall decrement the reference 52 | counter by 1 before checking if the deallocator needs to be called. 53 | .PP 54 | The 55 | .BR sref () 56 | function creates a new reference to 57 | .IR "ptr" , 58 | incrementing the internal reference counter of the smart shared pointer by 1. 59 | It shall only be called on a shared pointer. 60 | .PP 61 | The 62 | .BR unique_ptr () 63 | and 64 | .BR shared_ptr () 65 | macros expand to a call to the 66 | .BR smalloc () 67 | function with either UNIQUE or SHARED for the 68 | .I kind 69 | parameter, then sets the newly returned memory with 70 | .IR Value . 71 | Additional parameters are passed as-is to the function. 72 | If 73 | .I Type 74 | is an array type, then 75 | .I size 76 | shall contain the size of the compound type, and 77 | .I nmemb 78 | shall contain the length of the array. Otherwise, if 79 | .I Type 80 | is a scalar or complex type, then 81 | .I size 82 | shall contain the size of the type, and 83 | .I nmemb 84 | shall be 0. 85 | .SH RETURN VALUE 86 | The 87 | .BR smalloc () 88 | function return a pointer to the newly allocated memory. 89 | On error, it returns NULL. 90 | NULL may also be returned by a successful call to 91 | .BR smalloc () 92 | with a 93 | .I size 94 | of zero. 95 | .PP 96 | The 97 | .BR sfree () 98 | function returns no value. 99 | .PP 100 | The 101 | .BR sref () 102 | function returns 103 | .IR "ptr" . 104 | 105 | .SH SEE ALSO 106 | .ad l 107 | .nh 108 | .BR malloc (3) 109 | -------------------------------------------------------------------------------- /include/csptr/array.h: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright © 2015-2016 Franklin "Snaipe" Mathieu 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | #ifndef CSPTR_ARRAY_H_ 26 | # define CSPTR_ARRAY_H_ 27 | 28 | # include "common.h" 29 | # include "smart_ptr.h" 30 | 31 | typedef struct { 32 | size_t nmemb; 33 | size_t size; 34 | } s_meta_array; 35 | 36 | CSPTR_PURE size_t array_length(void *ptr); 37 | 38 | CSPTR_PURE size_t array_type_size(void *ptr); 39 | 40 | CSPTR_PURE void *array_user_meta(void *ptr); 41 | 42 | 43 | #endif /* !CSPTR_ARRAY_H_ */ 44 | -------------------------------------------------------------------------------- /include/csptr/common.h: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright © 2015-2016 Franklin "Snaipe" Mathieu 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | #ifndef CSPTR_COMMON_H_ 25 | # define CSPTR_COMMON_H_ 26 | 27 | # ifdef __GNUC__ 28 | # define CSPTR_INLINE __attribute__ ((always_inline)) inline 29 | # define CSPTR_MALLOC_API __attribute__ ((malloc)) 30 | # define CSPTR_PURE __attribute__ ((pure)) 31 | # elif defined(_MSC_VER) 32 | # define CSPTR_INLINE __forceinline 33 | # define CSPTR_MALLOC_API 34 | # define CSPTR_PURE 35 | # else 36 | # define CSPTR_INLINE 37 | # define CSPTR_MALLOC_API 38 | # define CSPTR_PURE 39 | # endif 40 | 41 | #endif /* !CSPTR_COMMON_H_ */ 42 | -------------------------------------------------------------------------------- /include/csptr/smalloc.h: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright © 2015-2016 Franklin "Snaipe" Mathieu 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | #ifndef CSPTR_SMALLOC_H_ 26 | # define CSPTR_SMALLOC_H_ 27 | 28 | # include 29 | # include "config.h" 30 | # include "common.h" 31 | 32 | # ifdef CSPTR_NO_SENTINEL 33 | # ifndef __GNUC__ 34 | # error Variadic structure sentinels can only be disabled on a compiler supporting GNU extensions 35 | # endif 36 | # define CSPTR_SENTINEL 37 | # define CSPTR_SENTINEL_DEC 38 | # else 39 | # define CSPTR_SENTINEL .sentinel_ = 0, 40 | # define CSPTR_SENTINEL_DEC int sentinel_; 41 | # endif 42 | 43 | enum pointer_kind { 44 | UNIQUE, 45 | SHARED, 46 | 47 | ARRAY = 1 << 8 48 | }; 49 | 50 | typedef void (*f_destructor)(void *, void *); 51 | 52 | typedef struct { 53 | void *(*alloc)(size_t); 54 | void (*dealloc)(void *); 55 | } s_allocator; 56 | 57 | extern s_allocator smalloc_allocator; 58 | 59 | typedef struct { 60 | CSPTR_SENTINEL_DEC 61 | size_t size; 62 | size_t nmemb; 63 | enum pointer_kind kind; 64 | f_destructor dtor; 65 | struct { 66 | const void *data; 67 | size_t size; 68 | } meta; 69 | } s_smalloc_args; 70 | 71 | CSPTR_PURE void *get_smart_ptr_meta(void *ptr); 72 | void *sref(void *ptr); 73 | CSPTR_MALLOC_API void *smalloc(s_smalloc_args *args); 74 | void sfree(void *ptr); 75 | void *smove_size(void *ptr, size_t size); 76 | 77 | # define smalloc(...) \ 78 | smalloc(&(s_smalloc_args) { CSPTR_SENTINEL __VA_ARGS__ }) 79 | 80 | # define smove(Ptr) \ 81 | smove_size((Ptr), sizeof (*(Ptr))) 82 | 83 | #endif /* !CSPTR_SMALLOC_H_ */ 84 | -------------------------------------------------------------------------------- /include/csptr/smart_ptr.h: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright © 2015-2016 Franklin "Snaipe" Mathieu 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | #ifndef CSPTR_SMART_PTR_H_ 26 | # define CSPTR_SMART_PTR_H_ 27 | 28 | # include 29 | # include "common.h" 30 | # include "smalloc.h" 31 | 32 | CSPTR_INLINE void sfree_stack(void *ptr) { 33 | union { 34 | void **real_ptr; 35 | void *ptr; 36 | } conv; 37 | conv.ptr = ptr; 38 | sfree(*conv.real_ptr); 39 | *conv.real_ptr = NULL; 40 | } 41 | 42 | # define ARGS_ args.dtor, { args.meta.ptr, args.meta.size } 43 | 44 | # define smart __attribute__ ((cleanup(sfree_stack))) 45 | # define smart_ptr(Kind, Type, ...) \ 46 | ({ \ 47 | struct s_tmp { \ 48 | CSPTR_SENTINEL_DEC \ 49 | __typeof__(Type) value; \ 50 | f_destructor dtor; \ 51 | struct { \ 52 | const void *ptr; \ 53 | size_t size; \ 54 | } meta; \ 55 | } args = { \ 56 | CSPTR_SENTINEL \ 57 | __VA_ARGS__ \ 58 | }; \ 59 | const __typeof__(Type[1]) dummy; \ 60 | void *var = sizeof (dummy[0]) == sizeof (dummy) \ 61 | ? smalloc(sizeof (Type), 0, Kind, ARGS_) \ 62 | : smalloc(sizeof (dummy[0]), \ 63 | sizeof (dummy) / sizeof (dummy[0]), Kind, ARGS_); \ 64 | if (var != NULL) \ 65 | memcpy(var, &args.value, sizeof (Type)); \ 66 | var; \ 67 | }) 68 | 69 | # define smart_arr(Kind, Type, Length, ...) \ 70 | ({ \ 71 | struct s_tmp { \ 72 | CSPTR_SENTINEL_DEC \ 73 | __typeof__(__typeof__(Type)[Length]) value; \ 74 | f_destructor dtor; \ 75 | struct { \ 76 | const void *ptr; \ 77 | size_t size; \ 78 | } meta; \ 79 | } args = { \ 80 | CSPTR_SENTINEL \ 81 | __VA_ARGS__ \ 82 | }; \ 83 | void *var = smalloc(sizeof (Type), Length, Kind, ARGS_); \ 84 | if (var != NULL) \ 85 | memcpy(var, &args.value, sizeof (Type)); \ 86 | var; \ 87 | }) 88 | 89 | # define shared_ptr(Type, ...) smart_ptr(SHARED, Type, __VA_ARGS__) 90 | # define unique_ptr(Type, ...) smart_ptr(UNIQUE, Type, __VA_ARGS__) 91 | 92 | # define shared_arr(Type, Length, ...) smart_arr(SHARED, Type, Length, __VA_ARGS__) 93 | # define unique_arr(Type, Length, ...) smart_arr(UNIQUE, Type, Length, __VA_ARGS__) 94 | 95 | #endif /* !CSPTR_SMART_PTR_H_ */ 96 | -------------------------------------------------------------------------------- /src/array.c: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright © 2015-2017 Franklin "Snaipe" Mathieu 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | #include "array.h" 25 | 26 | CSPTR_PURE size_t array_length(void *ptr) { 27 | s_meta_array *meta = get_smart_ptr_meta(ptr); 28 | return meta ? meta->nmemb : 0; 29 | } 30 | 31 | CSPTR_PURE size_t array_type_size(void *ptr) { 32 | s_meta_array *meta = get_smart_ptr_meta(ptr); 33 | return meta ? meta->size : 0; 34 | } 35 | 36 | CSPTR_PURE CSPTR_INLINE void *array_user_meta(void *ptr) { 37 | s_meta_array *meta = get_smart_ptr_meta(ptr); 38 | return meta ? meta + 1 : NULL; 39 | } 40 | -------------------------------------------------------------------------------- /src/config.h.in: -------------------------------------------------------------------------------- 1 | #ifndef CSPTR_CONFIG_H_IN_ 2 | # define CSPTR_CONFIG_H_IN_ 3 | 4 | #cmakedefine SMALLOC_FIXED_ALLOCATOR 1 5 | #cmakedefine CSPTR_NO_SENTINEL 1 6 | 7 | # define CSPTR_PACKAGE "${PROJECT_NAME}" 8 | # define CSPTR_VERSION "${PROJECT_VERSION}" 9 | 10 | #endif /* !CSPTR_CONFIG_H_IN_ */ 11 | -------------------------------------------------------------------------------- /src/mman.c: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright © 2015-2016 Franklin "Snaipe" Mathieu 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | #include "mman.h" 32 | #include "array.h" 33 | #undef smalloc 34 | 35 | s_allocator smalloc_allocator = {malloc, free}; 36 | 37 | #ifdef _MSC_VER 38 | # include 39 | # include 40 | #endif 41 | 42 | #ifndef _MSC_VER 43 | static CSPTR_INLINE size_t atomic_add(volatile size_t *count, const size_t limit, const size_t val) { 44 | size_t old_count, new_count; 45 | do { 46 | old_count = *count; 47 | if (old_count == limit) 48 | abort(); 49 | new_count = old_count + val; 50 | } while (!__sync_bool_compare_and_swap(count, old_count, new_count)); 51 | return new_count; 52 | } 53 | #endif 54 | 55 | static CSPTR_INLINE size_t atomic_increment(volatile size_t *count) { 56 | #ifdef _MSC_VER 57 | return InterlockedIncrement64(count); 58 | #else 59 | return atomic_add(count, SIZE_MAX, 1); 60 | #endif 61 | } 62 | 63 | static CSPTR_INLINE size_t atomic_decrement(volatile size_t *count) { 64 | #ifdef _MSC_VER 65 | return InterlockedDecrement64(count); 66 | #else 67 | return atomic_add(count, 0, -1); 68 | #endif 69 | } 70 | 71 | CSPTR_INLINE void *get_smart_ptr_meta(void *ptr) { 72 | assert((size_t) ptr == align((size_t) ptr)); 73 | 74 | s_meta *meta = get_meta(ptr); 75 | assert(meta->ptr == ptr); 76 | 77 | size_t head_size = meta->kind & SHARED ? sizeof (s_meta_shared) : sizeof (s_meta); 78 | size_t *metasize = (size_t *) ptr - 1; 79 | if (*metasize == head_size) 80 | return NULL; 81 | 82 | return (char *) meta + head_size; 83 | } 84 | 85 | void *sref(void *ptr) { 86 | s_meta *meta = get_meta(ptr); 87 | assert(meta->ptr == ptr); 88 | assert(meta->kind & SHARED); 89 | atomic_increment(&((s_meta_shared *) meta)->ref_count); 90 | return ptr; 91 | } 92 | 93 | void *smove_size(void *ptr, size_t size) { 94 | s_meta *meta = get_meta(ptr); 95 | assert(meta->kind & UNIQUE); 96 | 97 | s_smalloc_args args; 98 | 99 | size_t *metasize = (size_t *) ptr - 1; 100 | if (meta->kind & ARRAY) { 101 | s_meta_array *arr_meta = get_smart_ptr_meta(ptr); 102 | args = (s_smalloc_args) { 103 | .size = arr_meta->size * arr_meta->nmemb, 104 | .kind = (enum pointer_kind) (SHARED | ARRAY), 105 | .dtor = meta->dtor, 106 | .meta = { arr_meta, *metasize }, 107 | }; 108 | } else { 109 | void *user_meta = get_smart_ptr_meta(ptr); 110 | args = (s_smalloc_args) { 111 | .size = size, 112 | .kind = SHARED, 113 | .dtor = meta->dtor, 114 | .meta = { user_meta, *metasize }, 115 | }; 116 | } 117 | 118 | void *newptr = smalloc(&args); 119 | memcpy(newptr, ptr, size); 120 | return newptr; 121 | } 122 | 123 | CSPTR_MALLOC_API 124 | CSPTR_INLINE static void *alloc_entry(size_t head, size_t size, size_t metasize) { 125 | const size_t totalsize = head + size + metasize + sizeof (size_t); 126 | #ifdef SMALLOC_FIXED_ALLOCATOR 127 | return malloc(totalsize); 128 | #else /* !SMALLOC_FIXED_ALLOCATOR */ 129 | return smalloc_allocator.alloc(totalsize); 130 | #endif /* !SMALLOC_FIXED_ALLOCATOR */ 131 | } 132 | 133 | CSPTR_INLINE static void dealloc_entry(s_meta *meta, void *ptr) { 134 | if (meta->dtor) { 135 | void *user_meta = get_smart_ptr_meta(ptr); 136 | if (meta->kind & ARRAY) { 137 | s_meta_array *arr_meta = (void *) (meta + 1); 138 | for (size_t i = 0; i < arr_meta->nmemb; ++i) 139 | meta->dtor((char *) ptr + arr_meta->size * i, user_meta); 140 | } else 141 | meta->dtor(ptr, user_meta); 142 | } 143 | 144 | #ifdef SMALLOC_FIXED_ALLOCATOR 145 | free(meta); 146 | #else /* !SMALLOC_FIXED_ALLOCATOR */ 147 | smalloc_allocator.dealloc(meta); 148 | #endif /* !SMALLOC_FIXED_ALLOCATOR */ 149 | } 150 | 151 | CSPTR_MALLOC_API 152 | static void *smalloc_impl(s_smalloc_args *args) { 153 | if (!args->size) 154 | return NULL; 155 | 156 | // align the sizes to the size of a word 157 | size_t aligned_metasize = align(args->meta.size); 158 | size_t size = align(args->size); 159 | 160 | size_t head_size = args->kind & SHARED ? sizeof (s_meta_shared) : sizeof (s_meta); 161 | s_meta_shared *ptr = alloc_entry(head_size, size, aligned_metasize); 162 | if (ptr == NULL) 163 | return NULL; 164 | 165 | char *shifted = (char *) ptr + head_size; 166 | if (args->meta.size && args->meta.data) 167 | memcpy(shifted, args->meta.data, args->meta.size); 168 | 169 | size_t *sz = (size_t *) (shifted + aligned_metasize); 170 | *sz = head_size + aligned_metasize; 171 | 172 | *(s_meta*) ptr = (s_meta) { 173 | .kind = args->kind, 174 | .dtor = args->dtor, 175 | #ifndef NDEBUG 176 | .ptr = sz + 1 177 | #endif 178 | }; 179 | 180 | if (args->kind & SHARED) 181 | ptr->ref_count = 1; 182 | 183 | return sz + 1; 184 | } 185 | 186 | CSPTR_MALLOC_API 187 | CSPTR_INLINE static void *smalloc_array(s_smalloc_args *args) { 188 | const size_t size = align(args->meta.size + sizeof(s_meta_array)); 189 | #ifdef _MSC_VER 190 | char *new_meta = _alloca(size); 191 | #else 192 | char new_meta[size]; 193 | #endif 194 | s_meta_array *arr_meta = (void *) new_meta; 195 | *arr_meta = (s_meta_array) { 196 | .size = args->size, 197 | .nmemb = args->nmemb, 198 | }; 199 | memcpy(arr_meta + 1, args->meta.data, args->meta.size); 200 | return smalloc_impl(&(s_smalloc_args) { 201 | .size = args->nmemb * args->size, 202 | .kind = (enum pointer_kind) (args->kind | ARRAY), 203 | .dtor = args->dtor, 204 | .meta = { &new_meta, size }, 205 | }); 206 | } 207 | 208 | CSPTR_MALLOC_API 209 | void *smalloc(s_smalloc_args *args) { 210 | return (args->nmemb == 0 ? smalloc_impl : smalloc_array)(args); 211 | } 212 | 213 | void sfree(void *ptr) { 214 | if (!ptr) return; 215 | 216 | assert((size_t) ptr == align((size_t) ptr)); 217 | s_meta *meta = get_meta(ptr); 218 | assert(meta->ptr == ptr); 219 | 220 | if (meta->kind & SHARED && atomic_decrement(&((s_meta_shared *) meta)->ref_count)) 221 | return; 222 | 223 | dealloc_entry(meta, ptr); 224 | } 225 | -------------------------------------------------------------------------------- /src/mman.h: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright © 2015-2016 Franklin "Snaipe" Mathieu 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | #ifndef CSPTR_MMAN_H_ 26 | # define CSPTR_MMAN_H_ 27 | 28 | # include "smalloc.h" 29 | 30 | typedef struct { 31 | enum pointer_kind kind; 32 | f_destructor dtor; 33 | #ifndef NDEBUG 34 | void *ptr; 35 | #endif /* !NDEBUG */ 36 | } s_meta; 37 | 38 | typedef struct { 39 | enum pointer_kind kind; 40 | f_destructor dtor; 41 | #ifndef NDEBUG 42 | void *ptr; 43 | #endif /* !NDEBUG */ 44 | volatile size_t ref_count; 45 | } s_meta_shared; 46 | 47 | CSPTR_INLINE size_t align(size_t s) { 48 | return (s + (sizeof (char *) - 1)) & ~(sizeof (char *) - 1); 49 | } 50 | 51 | CSPTR_PURE CSPTR_INLINE s_meta *get_meta(void *ptr) { 52 | size_t *size = (size_t *) ptr - 1; 53 | return (s_meta *) ((char *) size - *size); 54 | } 55 | 56 | #endif /* !CSPTR_MMAN_H_ */ 57 | --------------------------------------------------------------------------------