tholenst | 0b5726e | 2021-04-13 23:16:58 -0700 | [diff] [blame] | 1 | # Copyright 2019 Google LLC |
| 2 | # |
Tink Team | a731c60 | 2019-03-14 05:32:13 -0700 | [diff] [blame] | 3 | # Licensed under the Apache License, Version 2.0 (the "License"); |
| 4 | # you may not use this file except in compliance with the License. |
| 5 | # You may obtain a copy of the License at |
| 6 | # |
| 7 | # http://www.apache.org/licenses/LICENSE-2.0 |
| 8 | # |
| 9 | # Unless required by applicable law or agreed to in writing, software |
| 10 | # distributed under the License is distributed on an "AS IS" BASIS, |
| 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 12 | # See the License for the specific language governing permissions and |
| 13 | # limitations under the License. |
| 14 | # |
| 15 | # Partially adapted from Abseil's CMake helpers |
| 16 | # https://github.com/abseil/abseil-cpp/blob/master/CMake/AbseilHelpers.cmake |
| 17 | |
| 18 | # Rules for declaring Tink targets in a way similar to Bazel. |
| 19 | # |
| 20 | # These functions are intended to reduce the difficulty of supporting completely |
| 21 | # different build systems, and are designed for Tink internal usage only. |
| 22 | # They may work outside this project too, but we don't support that. |
| 23 | # |
| 24 | # A set of global variables influences the behavior of the rules: |
| 25 | # |
| 26 | # TINK_MODULE name used to build more descriptive names and for namespaces. |
| 27 | # TINK_GENFILE_DIR generated content root, such pb.{cc,h} files. |
| 28 | # TINK_INCLUDE_DIRS list of global include paths. |
| 29 | # TINK_CXX_STANDARD C++ standard to enforce, 11 for now. |
Tink Team | 4dd3b07 | 2019-03-19 08:39:12 -0700 | [diff] [blame] | 30 | # TINK_BUILD_TESTS flag, set to false to disable tests (default false). |
Tink Team | a731c60 | 2019-03-14 05:32:13 -0700 | [diff] [blame] | 31 | # |
| 32 | # Sensible defaults are provided for all variables, except TINK_MODULE, which is |
| 33 | # defined by calls to tink_module(). Please don't alter it directly. |
| 34 | |
| 35 | include(CMakeParseArguments) |
przydatek | 9582134 | 2019-05-17 16:37:14 +0200 | [diff] [blame] | 36 | |
Tink Team | 4dd3b07 | 2019-03-19 08:39:12 -0700 | [diff] [blame] | 37 | if (TINK_BUILD_TESTS) |
Tink Team | a731c60 | 2019-03-14 05:32:13 -0700 | [diff] [blame] | 38 | enable_testing() |
| 39 | endif() |
| 40 | |
| 41 | if (NOT DEFINED TINK_GENFILE_DIR) |
| 42 | set(TINK_GENFILE_DIR "${PROJECT_BINARY_DIR}/__generated") |
| 43 | endif() |
| 44 | |
| 45 | if (NOT DEFINED TINK_CXX_STANDARD) |
ambrosin | f400c39 | 2022-09-22 04:37:25 -0700 | [diff] [blame] | 46 | set(TINK_CXX_STANDARD 14) |
Carlos Bernal | 40d890c | 2021-06-13 15:13:52 +0200 | [diff] [blame] | 47 | if (DEFINED CMAKE_CXX_STANDARD_REQUIRED AND CMAKE_CXX_STANDARD_REQUIRED AND DEFINED CMAKE_CXX_STANDARD) |
| 48 | set(TINK_CXX_STANDARD ${CMAKE_CXX_STANDARD}) |
| 49 | endif() |
Tink Team | a731c60 | 2019-03-14 05:32:13 -0700 | [diff] [blame] | 50 | endif() |
| 51 | |
ambrosin | a48b971 | 2023-07-10 07:24:50 -0700 | [diff] [blame] | 52 | set(TINK_DEFAULT_COPTS "") |
| 53 | if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") |
| 54 | # This is required to avoid error C1128. |
| 55 | # See https://learn.microsoft.com/en-us/cpp/error-messages/compiler-errors-1/fatal-error-c1128?view=msvc-170. |
| 56 | set(TINK_DEFAULT_COPTS "/bigobj") |
| 57 | endif() |
| 58 | |
Tink Team | a731c60 | 2019-03-14 05:32:13 -0700 | [diff] [blame] | 59 | list(APPEND TINK_INCLUDE_DIRS "${TINK_GENFILE_DIR}") |
| 60 | |
Tink Team | c3ef5a7 | 2019-03-19 08:37:20 -0700 | [diff] [blame] | 61 | set(TINK_IDE_FOLDER "Tink") |
| 62 | |
ambrosin | a2f527c | 2022-01-24 09:36:17 -0800 | [diff] [blame] | 63 | set(TINK_TARGET_EXCLUDE_IF_OPENSSL "exclude_if_openssl") |
ambrosin | 5dc5dd7 | 2023-02-08 01:11:57 -0800 | [diff] [blame] | 64 | set(TINK_TARGET_EXCLUDE_IF_WINDOWS "exclude_if_windows") |
ambrosin | a2f527c | 2022-01-24 09:36:17 -0800 | [diff] [blame] | 65 | |
Tink Team | a731c60 | 2019-03-14 05:32:13 -0700 | [diff] [blame] | 66 | # Declare the beginning of a new Tink library namespace. |
| 67 | # |
| 68 | # As a rule of thumb, every CMakeLists.txt should be a different module, named |
| 69 | # after the directory that contains it, and this function should appear at the |
| 70 | # top of each CMakeLists script. |
| 71 | # |
| 72 | # This is not a requirement, though. Targets should be grouped logically, and |
| 73 | # multiple directories can be part of the same module as long as target names |
| 74 | # do not collide. |
| 75 | # |
| 76 | macro(tink_module NAME) |
| 77 | set(TINK_MODULE ${NAME}) |
| 78 | endmacro() |
| 79 | |
| 80 | # Declare a Tink library. Produces a static library that can be linked into |
| 81 | # other test, binary or library targets. Tink libraries are mainly meant as |
| 82 | # a way to organise code and speed up compilation. |
| 83 | # |
| 84 | # Arguments: |
ambrosin | 49fcc81 | 2023-04-26 01:38:59 -0700 | [diff] [blame] | 85 | # NAME base name of the target. See below for target naming conventions. |
| 86 | # SRCS list of source files, including headers. |
| 87 | # DEPS list of dependency targets. |
| 88 | # PUBLIC flag, signals that this target is intended for external use. |
| 89 | # TESTONLY flag, signals that this target should be ignored if |
| 90 | # TINK_BUILD_TESTS=OFF. |
Tink Team | a731c60 | 2019-03-14 05:32:13 -0700 | [diff] [blame] | 91 | # |
| 92 | # If SRCS contains only headers, an INTERFACE rule is created. This rule carries |
| 93 | # include path and link library information, but is not directly buildable. |
| 94 | # |
| 95 | # The corresponding build target is named tink_<MODULE>_<NAME> if PUBLIC is |
| 96 | # specified, or tink_internal_<MODULE>_<NAME> otherwise. An alias is also |
| 97 | # defined for use in CMake scripts, in the tink::<MODULE>::<NAME> form. |
| 98 | # |
| 99 | # Unlike Bazel, CMake does not enforce the rule that all dependencies must be |
| 100 | # listed. CMake DEPS just carry include, build and link flags that are passed |
| 101 | # to the compiler. Because of this, a target might compile even if a dependency |
| 102 | # is not specified, but that could break at any time. So make sure that all |
| 103 | # dependencies are explicitly specified. |
| 104 | # |
| 105 | function(tink_cc_library) |
| 106 | cmake_parse_arguments(PARSE_ARGV 0 tink_cc_library |
ambrosin | 49fcc81 | 2023-04-26 01:38:59 -0700 | [diff] [blame] | 107 | "PUBLIC;TESTONLY" |
Tink Team | a731c60 | 2019-03-14 05:32:13 -0700 | [diff] [blame] | 108 | "NAME" |
ambrosin | a2f527c | 2022-01-24 09:36:17 -0800 | [diff] [blame] | 109 | "SRCS;DEPS;TAGS" |
Tink Team | a731c60 | 2019-03-14 05:32:13 -0700 | [diff] [blame] | 110 | ) |
| 111 | |
ambrosin | 49fcc81 | 2023-04-26 01:38:59 -0700 | [diff] [blame] | 112 | if (tink_cc_library_TESTONLY AND NOT TINK_BUILD_TESTS) |
| 113 | return() |
| 114 | endif() |
| 115 | |
Tink Team | a731c60 | 2019-03-14 05:32:13 -0700 | [diff] [blame] | 116 | if (NOT DEFINED TINK_MODULE) |
| 117 | message(FATAL_ERROR |
| 118 | "TINK_MODULE not defined, perhaps you are missing a tink_module() statement?") |
| 119 | endif() |
| 120 | |
ambrosin | 5dc5dd7 | 2023-02-08 01:11:57 -0800 | [diff] [blame] | 121 | # Check if this target must be skipped. |
ambrosin | a2f527c | 2022-01-24 09:36:17 -0800 | [diff] [blame] | 122 | foreach(_tink_cc_library_tag ${tink_cc_library_TAGS}) |
ambrosin | 5dc5dd7 | 2023-02-08 01:11:57 -0800 | [diff] [blame] | 123 | # Exclude if we use OpenSSL. |
ambrosin | a2f527c | 2022-01-24 09:36:17 -0800 | [diff] [blame] | 124 | if (${_tink_cc_library_tag} STREQUAL ${TINK_TARGET_EXCLUDE_IF_OPENSSL} AND TINK_USE_SYSTEM_OPENSSL) |
| 125 | return() |
| 126 | endif() |
ambrosin | 5dc5dd7 | 2023-02-08 01:11:57 -0800 | [diff] [blame] | 127 | # Exclude if building on Windows. |
| 128 | if (${_tink_cc_library_tag} STREQUAL ${TINK_TARGET_EXCLUDE_IF_WINDOWS} AND WIN32) |
| 129 | return() |
| 130 | endif() |
ambrosin | a2f527c | 2022-01-24 09:36:17 -0800 | [diff] [blame] | 131 | endforeach() |
| 132 | |
tholenst | 7c85e1a | 2020-03-04 05:52:35 -0800 | [diff] [blame] | 133 | # We replace :: with __ in targets, because :: may not appear in target names. |
| 134 | # However, the module name should still span multiple name spaces. |
| 135 | STRING(REPLACE "::" "__" _ESCAPED_TINK_MODULE ${TINK_MODULE}) |
| 136 | |
Tink Team | a731c60 | 2019-03-14 05:32:13 -0700 | [diff] [blame] | 137 | set(_is_headers_only_lib true) |
| 138 | foreach(_src_file ${tink_cc_library_SRCS}) |
| 139 | if(${_src_file} MATCHES "\\.cc$") |
| 140 | set(_is_headers_only_lib false) |
| 141 | break() |
| 142 | endif() |
| 143 | endforeach() |
| 144 | |
| 145 | if (tink_cc_library_PUBLIC) |
tholenst | 7c85e1a | 2020-03-04 05:52:35 -0800 | [diff] [blame] | 146 | set(_target_name "tink_${_ESCAPED_TINK_MODULE}_${tink_cc_library_NAME}") |
Tink Team | a731c60 | 2019-03-14 05:32:13 -0700 | [diff] [blame] | 147 | else() |
tholenst | 7c85e1a | 2020-03-04 05:52:35 -0800 | [diff] [blame] | 148 | set(_target_name "tink_internal_${_ESCAPED_TINK_MODULE}_${tink_cc_library_NAME}") |
Tink Team | a731c60 | 2019-03-14 05:32:13 -0700 | [diff] [blame] | 149 | endif() |
| 150 | |
| 151 | if(NOT _is_headers_only_lib) |
| 152 | add_library(${_target_name} STATIC "") |
| 153 | target_sources(${_target_name} PRIVATE ${tink_cc_library_SRCS}) |
| 154 | target_include_directories(${_target_name} PUBLIC ${TINK_INCLUDE_DIRS}) |
| 155 | target_link_libraries(${_target_name} PUBLIC ${tink_cc_library_DEPS}) |
ambrosin | a48b971 | 2023-07-10 07:24:50 -0700 | [diff] [blame] | 156 | target_compile_options(${_target_name} PRIVATE ${TINK_DEFAULT_COPTS}) |
Tink Team | a731c60 | 2019-03-14 05:32:13 -0700 | [diff] [blame] | 157 | set_property(TARGET ${_target_name} PROPERTY CXX_STANDARD ${TINK_CXX_STANDARD}) |
| 158 | set_property(TARGET ${_target_name} PROPERTY CXX_STANDARD_REQUIRED true) |
Tink Team | c3ef5a7 | 2019-03-19 08:37:20 -0700 | [diff] [blame] | 159 | if (tink_cc_library_PUBLIC) |
| 160 | set_property(TARGET ${_target_name} |
| 161 | PROPERTY FOLDER "${TINK_IDE_FOLDER}") |
| 162 | else() |
| 163 | set_property(TARGET ${_target_name} |
| 164 | PROPERTY FOLDER "${TINK_IDE_FOLDER}/Internal") |
| 165 | endif() |
Tink Team | a731c60 | 2019-03-14 05:32:13 -0700 | [diff] [blame] | 166 | else() |
| 167 | add_library(${_target_name} INTERFACE) |
| 168 | target_include_directories(${_target_name} INTERFACE ${TINK_INCLUDE_DIRS}) |
| 169 | target_link_libraries(${_target_name} INTERFACE ${tink_cc_library_DEPS}) |
| 170 | endif() |
| 171 | |
| 172 | add_library( |
| 173 | tink::${TINK_MODULE}::${tink_cc_library_NAME} ALIAS ${_target_name}) |
| 174 | endfunction(tink_cc_library) |
| 175 | |
przydatek | 9582134 | 2019-05-17 16:37:14 +0200 | [diff] [blame] | 176 | # Declare a Tink test using googletest, with a syntax similar to Bazel. |
Tink Team | a731c60 | 2019-03-14 05:32:13 -0700 | [diff] [blame] | 177 | # |
| 178 | # Parameters: |
ambrosin | 49fcc81 | 2023-04-26 01:38:59 -0700 | [diff] [blame] | 179 | # NAME base name of the test. |
| 180 | # SRCS list of test source files, headers included. |
| 181 | # DEPS list of dependencies, see tink_cc_library above. |
| 182 | # DATA list of non-code dependencies, such as test vectors. |
Tink Team | a731c60 | 2019-03-14 05:32:13 -0700 | [diff] [blame] | 183 | # |
| 184 | # Tests added with this macro are automatically registered. |
| 185 | # Each test produces a build target named tink_test_<MODULE>_<NAME>. |
| 186 | # |
| 187 | function(tink_cc_test) |
| 188 | cmake_parse_arguments(PARSE_ARGV 0 tink_cc_test |
| 189 | "" |
| 190 | "NAME" |
ambrosin | a2f527c | 2022-01-24 09:36:17 -0800 | [diff] [blame] | 191 | "SRCS;DEPS;DATA;TAGS" |
Tink Team | a731c60 | 2019-03-14 05:32:13 -0700 | [diff] [blame] | 192 | ) |
| 193 | |
Tink Team | 4dd3b07 | 2019-03-19 08:39:12 -0700 | [diff] [blame] | 194 | if (NOT TINK_BUILD_TESTS) |
Tink Team | a731c60 | 2019-03-14 05:32:13 -0700 | [diff] [blame] | 195 | return() |
| 196 | endif() |
| 197 | |
| 198 | if (NOT DEFINED TINK_MODULE) |
| 199 | message(FATAL_ERROR "TINK_MODULE not defined") |
| 200 | endif() |
| 201 | |
ambrosin | 5dc5dd7 | 2023-02-08 01:11:57 -0800 | [diff] [blame] | 202 | # Check if this target must be skipped. |
ambrosin | a2f527c | 2022-01-24 09:36:17 -0800 | [diff] [blame] | 203 | foreach(_tink_cc_test_tag ${tink_cc_test_TAGS}) |
ambrosin | 5dc5dd7 | 2023-02-08 01:11:57 -0800 | [diff] [blame] | 204 | # Exclude if we use OpenSSL. |
ambrosin | a2f527c | 2022-01-24 09:36:17 -0800 | [diff] [blame] | 205 | if (${_tink_cc_test_tag} STREQUAL ${TINK_TARGET_EXCLUDE_IF_OPENSSL} AND TINK_USE_SYSTEM_OPENSSL) |
| 206 | return() |
| 207 | endif() |
ambrosin | 5dc5dd7 | 2023-02-08 01:11:57 -0800 | [diff] [blame] | 208 | # Exclude if building on Windows. |
| 209 | if (${_tink_cc_test_tag} STREQUAL ${TINK_TARGET_EXCLUDE_IF_WINDOWS} AND WIN32) |
| 210 | return() |
| 211 | endif() |
ambrosin | a2f527c | 2022-01-24 09:36:17 -0800 | [diff] [blame] | 212 | endforeach() |
| 213 | |
tholenst | 7c85e1a | 2020-03-04 05:52:35 -0800 | [diff] [blame] | 214 | # We replace :: with __ in targets, because :: may not appear in target names. |
| 215 | # However, the module name should still span multiple name spaces. |
| 216 | STRING(REPLACE "::" "__" _ESCAPED_TINK_MODULE ${TINK_MODULE}) |
| 217 | |
| 218 | set(_target_name "tink_test_${_ESCAPED_TINK_MODULE}_${tink_cc_test_NAME}") |
Tink Team | a731c60 | 2019-03-14 05:32:13 -0700 | [diff] [blame] | 219 | |
| 220 | add_executable(${_target_name} |
| 221 | ${tink_cc_test_SRCS} |
| 222 | ) |
| 223 | |
| 224 | target_link_libraries(${_target_name} |
| 225 | gtest_main |
| 226 | ${tink_cc_test_DEPS} |
| 227 | ) |
| 228 | |
Tink Team | c3ef5a7 | 2019-03-19 08:37:20 -0700 | [diff] [blame] | 229 | set_property(TARGET ${_target_name} |
| 230 | PROPERTY FOLDER "${TINK_IDE_FOLDER}/Tests") |
tholenst | f019077 | 2019-06-17 06:41:34 -0700 | [diff] [blame] | 231 | set_property(TARGET ${_target_name} PROPERTY CXX_STANDARD ${TINK_CXX_STANDARD}) |
| 232 | set_property(TARGET ${_target_name} PROPERTY CXX_STANDARD_REQUIRED true) |
Tink Team | c3ef5a7 | 2019-03-19 08:37:20 -0700 | [diff] [blame] | 233 | |
ambrosin | f07d211 | 2022-01-26 05:24:35 -0800 | [diff] [blame] | 234 | # Note: This was preferred over using gtest_discover_tests because of [1]. |
| 235 | # [1] https://gitlab.kitware.com/cmake/cmake/-/issues/23039 |
| 236 | add_test(NAME ${_target_name} COMMAND ${_target_name} WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) |
Tink Team | a731c60 | 2019-03-14 05:32:13 -0700 | [diff] [blame] | 237 | endfunction(tink_cc_test) |
| 238 | |
| 239 | # Declare a C++ Proto library. |
| 240 | # |
| 241 | # Parameters: |
| 242 | # NAME base name of the library. |
| 243 | # SRCS list of .proto source files. |
| 244 | # DEPS list of proto library dependencies, produced by tink_cc_proto or not. |
| 245 | # |
| 246 | # The resulting library follows the same naming convention as tink_cc_library. |
| 247 | # |
| 248 | function(tink_cc_proto) |
| 249 | cmake_parse_arguments(PARSE_ARGV 0 tink_cc_proto |
| 250 | "" |
| 251 | "NAME" |
| 252 | "SRCS;DEPS" |
| 253 | ) |
| 254 | |
| 255 | set(tink_cc_proto_GEN_SRCS) |
| 256 | foreach(_src_path ${tink_cc_proto_SRCS}) |
| 257 | get_filename_component(_src_absolute_path "${_src_path}" ABSOLUTE) |
| 258 | get_filename_component(_src_basename "${_src_path}" NAME_WE) |
| 259 | get_filename_component(_src_dir "${_src_absolute_path}" DIRECTORY) |
| 260 | file(RELATIVE_PATH _src_rel_path "${PROJECT_SOURCE_DIR}" "${_src_dir}") |
| 261 | |
| 262 | set(_gen_srcs) |
| 263 | foreach(_gen_ext .pb.h .pb.cc) |
| 264 | list(APPEND _gen_srcs |
| 265 | "${TINK_GENFILE_DIR}/${_src_rel_path}/${_src_basename}${_gen_ext}") |
| 266 | endforeach() |
| 267 | |
| 268 | list(APPEND tink_cc_proto_GEN_SRCS ${_gen_srcs}) |
| 269 | |
| 270 | add_custom_command( |
| 271 | COMMAND protobuf::protoc |
| 272 | ARGS |
| 273 | --cpp_out "${TINK_GENFILE_DIR}" |
| 274 | -I "${PROJECT_SOURCE_DIR}" |
| 275 | "${_src_absolute_path}" |
| 276 | OUTPUT |
| 277 | ${_gen_srcs} |
| 278 | DEPENDS |
| 279 | protobuf::protoc |
| 280 | ${_src_absolute_path} |
| 281 | COMMENT "Running CXX protocol buffer compiler on ${_src_path}" |
| 282 | VERBATIM |
| 283 | ) |
| 284 | endforeach() |
| 285 | |
| 286 | set_source_files_properties( |
| 287 | ${tink_cc_proto_GEN_SRCS} PROPERTIES GENERATED true) |
| 288 | |
| 289 | tink_cc_library( |
| 290 | NAME ${tink_cc_proto_NAME} |
| 291 | SRCS ${tink_cc_proto_GEN_SRCS} |
| 292 | DEPS |
| 293 | protobuf::libprotoc |
| 294 | ${tink_cc_proto_DEPS} |
| 295 | ) |
| 296 | endfunction() |
| 297 | |
| 298 | # Declare an empty target, that depends on all those specified. Use this rule |
| 299 | # to group dependencies that are logically related and give them a single name. |
| 300 | # |
| 301 | # Parameters: |
ambrosin | 49fcc81 | 2023-04-26 01:38:59 -0700 | [diff] [blame] | 302 | # NAME base name of the target. |
| 303 | # DEPS list of dependencies to group. |
Tink Team | a731c60 | 2019-03-14 05:32:13 -0700 | [diff] [blame] | 304 | # |
| 305 | # Each tink_target_group produces a target named tink_<MODULE>_<NAME>. |
| 306 | function(tink_target_group) |
| 307 | cmake_parse_arguments(PARSE_ARGV 0 tink_target_group "" "NAME" "DEPS") |
| 308 | set(_target_name "tink_${TINK_MODULE}_${tink_target_group_NAME}") |
| 309 | add_custom_target(${_target_name}) |
| 310 | add_dependencies(${_target_name} ${tink_target_group_DEPS}) |
| 311 | endfunction() |