blob: 58bcc2570fc33701edefd22eca3e209711ab3d81 [file] [log] [blame]
tholenst0b5726e2021-04-13 23:16:58 -07001# Copyright 2019 Google LLC
2#
Tink Teama731c602019-03-14 05:32:13 -07003# 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 Team4dd3b072019-03-19 08:39:12 -070030# TINK_BUILD_TESTS flag, set to false to disable tests (default false).
Tink Teama731c602019-03-14 05:32:13 -070031#
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
35include(CMakeParseArguments)
przydatek95821342019-05-17 16:37:14 +020036
Tink Team4dd3b072019-03-19 08:39:12 -070037if (TINK_BUILD_TESTS)
Tink Teama731c602019-03-14 05:32:13 -070038 enable_testing()
39endif()
40
41if (NOT DEFINED TINK_GENFILE_DIR)
42 set(TINK_GENFILE_DIR "${PROJECT_BINARY_DIR}/__generated")
43endif()
44
45if (NOT DEFINED TINK_CXX_STANDARD)
ambrosinf400c392022-09-22 04:37:25 -070046 set(TINK_CXX_STANDARD 14)
Carlos Bernal40d890c2021-06-13 15:13:52 +020047 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 Teama731c602019-03-14 05:32:13 -070050endif()
51
ambrosina48b9712023-07-10 07:24:50 -070052set(TINK_DEFAULT_COPTS "")
53if(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")
57endif()
58
Tink Teama731c602019-03-14 05:32:13 -070059list(APPEND TINK_INCLUDE_DIRS "${TINK_GENFILE_DIR}")
60
Tink Teamc3ef5a72019-03-19 08:37:20 -070061set(TINK_IDE_FOLDER "Tink")
62
ambrosina2f527c2022-01-24 09:36:17 -080063set(TINK_TARGET_EXCLUDE_IF_OPENSSL "exclude_if_openssl")
ambrosin5dc5dd72023-02-08 01:11:57 -080064set(TINK_TARGET_EXCLUDE_IF_WINDOWS "exclude_if_windows")
ambrosina2f527c2022-01-24 09:36:17 -080065
Tink Teama731c602019-03-14 05:32:13 -070066# 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#
76macro(tink_module NAME)
77 set(TINK_MODULE ${NAME})
78endmacro()
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:
ambrosin49fcc812023-04-26 01:38:59 -070085# 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 Teama731c602019-03-14 05:32:13 -070091#
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#
105function(tink_cc_library)
106 cmake_parse_arguments(PARSE_ARGV 0 tink_cc_library
ambrosin49fcc812023-04-26 01:38:59 -0700107 "PUBLIC;TESTONLY"
Tink Teama731c602019-03-14 05:32:13 -0700108 "NAME"
ambrosina2f527c2022-01-24 09:36:17 -0800109 "SRCS;DEPS;TAGS"
Tink Teama731c602019-03-14 05:32:13 -0700110 )
111
ambrosin49fcc812023-04-26 01:38:59 -0700112 if (tink_cc_library_TESTONLY AND NOT TINK_BUILD_TESTS)
113 return()
114 endif()
115
Tink Teama731c602019-03-14 05:32:13 -0700116 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
ambrosin5dc5dd72023-02-08 01:11:57 -0800121 # Check if this target must be skipped.
ambrosina2f527c2022-01-24 09:36:17 -0800122 foreach(_tink_cc_library_tag ${tink_cc_library_TAGS})
ambrosin5dc5dd72023-02-08 01:11:57 -0800123 # Exclude if we use OpenSSL.
ambrosina2f527c2022-01-24 09:36:17 -0800124 if (${_tink_cc_library_tag} STREQUAL ${TINK_TARGET_EXCLUDE_IF_OPENSSL} AND TINK_USE_SYSTEM_OPENSSL)
125 return()
126 endif()
ambrosin5dc5dd72023-02-08 01:11:57 -0800127 # Exclude if building on Windows.
128 if (${_tink_cc_library_tag} STREQUAL ${TINK_TARGET_EXCLUDE_IF_WINDOWS} AND WIN32)
129 return()
130 endif()
ambrosina2f527c2022-01-24 09:36:17 -0800131 endforeach()
132
tholenst7c85e1a2020-03-04 05:52:35 -0800133 # 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 Teama731c602019-03-14 05:32:13 -0700137 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)
tholenst7c85e1a2020-03-04 05:52:35 -0800146 set(_target_name "tink_${_ESCAPED_TINK_MODULE}_${tink_cc_library_NAME}")
Tink Teama731c602019-03-14 05:32:13 -0700147 else()
tholenst7c85e1a2020-03-04 05:52:35 -0800148 set(_target_name "tink_internal_${_ESCAPED_TINK_MODULE}_${tink_cc_library_NAME}")
Tink Teama731c602019-03-14 05:32:13 -0700149 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})
ambrosina48b9712023-07-10 07:24:50 -0700156 target_compile_options(${_target_name} PRIVATE ${TINK_DEFAULT_COPTS})
Tink Teama731c602019-03-14 05:32:13 -0700157 set_property(TARGET ${_target_name} PROPERTY CXX_STANDARD ${TINK_CXX_STANDARD})
158 set_property(TARGET ${_target_name} PROPERTY CXX_STANDARD_REQUIRED true)
Tink Teamc3ef5a72019-03-19 08:37:20 -0700159 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 Teama731c602019-03-14 05:32:13 -0700166 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})
174endfunction(tink_cc_library)
175
przydatek95821342019-05-17 16:37:14 +0200176# Declare a Tink test using googletest, with a syntax similar to Bazel.
Tink Teama731c602019-03-14 05:32:13 -0700177#
178# Parameters:
ambrosin49fcc812023-04-26 01:38:59 -0700179# 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 Teama731c602019-03-14 05:32:13 -0700183#
184# Tests added with this macro are automatically registered.
185# Each test produces a build target named tink_test_<MODULE>_<NAME>.
186#
187function(tink_cc_test)
188 cmake_parse_arguments(PARSE_ARGV 0 tink_cc_test
189 ""
190 "NAME"
ambrosina2f527c2022-01-24 09:36:17 -0800191 "SRCS;DEPS;DATA;TAGS"
Tink Teama731c602019-03-14 05:32:13 -0700192 )
193
Tink Team4dd3b072019-03-19 08:39:12 -0700194 if (NOT TINK_BUILD_TESTS)
Tink Teama731c602019-03-14 05:32:13 -0700195 return()
196 endif()
197
198 if (NOT DEFINED TINK_MODULE)
199 message(FATAL_ERROR "TINK_MODULE not defined")
200 endif()
201
ambrosin5dc5dd72023-02-08 01:11:57 -0800202 # Check if this target must be skipped.
ambrosina2f527c2022-01-24 09:36:17 -0800203 foreach(_tink_cc_test_tag ${tink_cc_test_TAGS})
ambrosin5dc5dd72023-02-08 01:11:57 -0800204 # Exclude if we use OpenSSL.
ambrosina2f527c2022-01-24 09:36:17 -0800205 if (${_tink_cc_test_tag} STREQUAL ${TINK_TARGET_EXCLUDE_IF_OPENSSL} AND TINK_USE_SYSTEM_OPENSSL)
206 return()
207 endif()
ambrosin5dc5dd72023-02-08 01:11:57 -0800208 # Exclude if building on Windows.
209 if (${_tink_cc_test_tag} STREQUAL ${TINK_TARGET_EXCLUDE_IF_WINDOWS} AND WIN32)
210 return()
211 endif()
ambrosina2f527c2022-01-24 09:36:17 -0800212 endforeach()
213
tholenst7c85e1a2020-03-04 05:52:35 -0800214 # 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 Teama731c602019-03-14 05:32:13 -0700219
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 Teamc3ef5a72019-03-19 08:37:20 -0700229 set_property(TARGET ${_target_name}
230 PROPERTY FOLDER "${TINK_IDE_FOLDER}/Tests")
tholenstf0190772019-06-17 06:41:34 -0700231 set_property(TARGET ${_target_name} PROPERTY CXX_STANDARD ${TINK_CXX_STANDARD})
232 set_property(TARGET ${_target_name} PROPERTY CXX_STANDARD_REQUIRED true)
Tink Teamc3ef5a72019-03-19 08:37:20 -0700233
ambrosinf07d2112022-01-26 05:24:35 -0800234 # 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 Teama731c602019-03-14 05:32:13 -0700237endfunction(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#
248function(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 )
296endfunction()
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:
ambrosin49fcc812023-04-26 01:38:59 -0700302# NAME base name of the target.
303# DEPS list of dependencies to group.
Tink Teama731c602019-03-14 05:32:13 -0700304#
305# Each tink_target_group produces a target named tink_<MODULE>_<NAME>.
306function(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})
311endfunction()