• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1set(OBJECT_LIBRARY_TARGET_TYPE "OBJECT_LIBRARY")
2
3# Rule which is essentially a wrapper over add_library to compile a set of
4# sources to object files.
5# Usage:
6#     add_object_library(
7#       <target_name>
8#       HDRS <list of header files>
9#       SRCS <list of source files>
10#       DEPENDS <list of dependencies>
11#       COMPILE_OPTIONS <optional list of special compile options for this target>
12function(add_object_library target_name)
13  cmake_parse_arguments(
14    "ADD_OBJECT"
15    "" # No option arguments
16    "" # Single value arguments
17    "SRCS;HDRS;COMPILE_OPTIONS;DEPENDS" # Multivalue arguments
18    ${ARGN}
19  )
20
21  if(NOT ADD_OBJECT_SRCS)
22    message(FATAL_ERROR "'add_object_library' rule requires SRCS to be specified.")
23  endif()
24
25  get_fq_target_name(${target_name} fq_target_name)
26  add_library(
27    ${fq_target_name}
28    OBJECT
29    ${ADD_OBJECT_SRCS}
30    ${ADD_OBJECT_HDRS}
31  )
32  target_include_directories(
33    ${fq_target_name}
34    PRIVATE
35      ${LIBC_BUILD_DIR}/include
36      ${LIBC_SOURCE_DIR}
37      ${LIBC_BUILD_DIR}
38  )
39  if(ADD_OBJECT_COMPILE_OPTIONS)
40    target_compile_options(
41      ${fq_target_name}
42      PRIVATE ${ADD_OBJECT_COMPILE_OPTIONS}
43    )
44  endif()
45
46  get_fq_deps_list(fq_deps_list ${ADD_OBJECT_DEPENDS})
47  if(fq_deps_list)
48    add_dependencies(${fq_target_name} ${fq_deps_list})
49  endif()
50
51  set_target_properties(
52    ${fq_target_name}
53    PROPERTIES
54      "TARGET_TYPE" ${OBJECT_LIBRARY_TARGET_TYPE}
55      "OBJECT_FILES" "$<TARGET_OBJECTS:${fq_target_name}>"
56      "DEPS" "${fq_deps_list}"
57  )
58endfunction(add_object_library)
59
60set(ENTRYPOINT_OBJ_TARGET_TYPE "ENTRYPOINT_OBJ")
61
62# A rule for entrypoint object targets.
63# Usage:
64#     add_entrypoint_object(
65#       <target_name>
66#       [ALIAS|REDIRECTED] # Specified if the entrypoint is redirected or an alias.
67#       [NAME] <the C name of the entrypoint if different from target_name>
68#       SRCS <list of .cpp files>
69#       HDRS <list of .h files>
70#       DEPENDS <list of dependencies>
71#       COMPILE_OPTIONS <optional list of special compile options for this target>
72#       SPECIAL_OBJECTS <optional list of special object targets added by the rule `add_object`>
73#     )
74function(add_entrypoint_object target_name)
75  cmake_parse_arguments(
76    "ADD_ENTRYPOINT_OBJ"
77    "ALIAS;REDIRECTED" # Optional argument
78    "NAME" # Single value arguments
79    "SRCS;HDRS;DEPENDS;COMPILE_OPTIONS"  # Multi value arguments
80    ${ARGN}
81  )
82
83  get_fq_target_name(${target_name} fq_target_name)
84  set(entrypoint_name ${target_name})
85  if(ADD_ENTRYPOINT_OBJ_NAME)
86    set(entrypoint_name ${ADD_ENTRYPOINT_OBJ_NAME})
87  endif()
88
89  list(FIND TARGET_ENTRYPOINT_NAME_LIST ${entrypoint_name} entrypoint_name_index)
90  if(${entrypoint_name_index} EQUAL -1)
91    add_custom_target(${fq_target_name})
92    set_target_properties(
93      ${fq_target_name}
94      PROPERTIES
95        "ENTRYPOINT_NAME" ${entrypoint_name}
96        "TARGET_TYPE" ${ENTRYPOINT_OBJ_TARGET_TYPE}
97        "OBJECT_FILE" ""
98        "OBJECT_FILE_RAW" ""
99        "DEPS" ""
100        "SKIPPED" "YES"
101    )
102    message(STATUS "Skipping libc entrypoint ${fq_target_name}.")
103    return()
104  endif()
105
106  if(ADD_ENTRYPOINT_OBJ_ALIAS)
107    # Alias targets help one add aliases to other entrypoint object targets.
108    # One can use alias targets setup OS/machine independent entrypoint targets.
109    list(LENGTH ADD_ENTRYPOINT_OBJ_DEPENDS deps_size)
110    if(NOT (${deps_size} EQUAL "1"))
111      message(FATAL_ERROR "An entrypoint alias should have exactly one dependency.")
112    endif()
113    list(GET ADD_ENTRYPOINT_OBJ_DEPENDS 0 dep_target)
114    get_fq_dep_name(fq_dep_name ${dep_target})
115    if(NOT TARGET ${fq_dep_name})
116      message(WARNING "Aliasee ${fq_dep_name} for entrypoint alias ${target_name} missing; "
117                      "Target ${target_name} will be ignored.")
118      return()
119    endif()
120
121    get_target_property(obj_type ${fq_dep_name} "TARGET_TYPE")
122    if((NOT obj_type) OR (NOT (${obj_type} STREQUAL ${ENTRYPOINT_OBJ_TARGET_TYPE})))
123      message(FATAL_ERROR "The aliasee of an entrypoint alias should be an entrypoint.")
124    endif()
125
126    add_custom_target(${fq_target_name})
127    add_dependencies(${fq_target_name} ${fq_dep_name})
128    get_target_property(object_file ${fq_dep_name} "OBJECT_FILE")
129    get_target_property(object_file_raw ${fq_dep_name} "OBJECT_FILE_RAW")
130    set_target_properties(
131      ${fq_target_name}
132      PROPERTIES
133        "ENTRYPOINT_NAME" ${entrypoint_name}
134        "TARGET_TYPE" ${ENTRYPOINT_OBJ_TARGET_TYPE}
135        "IS_ALIAS" "YES"
136        "OBJECT_FILE" ""
137        "OBJECT_FILE_RAW" ""
138        "DEPS" "${fq_dep_name}"
139    )
140    return()
141  endif()
142
143  if(NOT ADD_ENTRYPOINT_OBJ_SRCS)
144    message(FATAL_ERROR "`add_entrypoint_object` rule requires SRCS to be specified.")
145  endif()
146  if(NOT ADD_ENTRYPOINT_OBJ_HDRS)
147    message(FATAL_ERROR "`add_entrypoint_object` rule requires HDRS to be specified.")
148  endif()
149
150  set(objects_target_name "${fq_target_name}_objects")
151
152  add_library(
153    ${objects_target_name}
154    # We want an object library as the objects will eventually get packaged into
155    # an archive (like libc.a).
156    OBJECT
157    ${ADD_ENTRYPOINT_OBJ_SRCS}
158    ${ADD_ENTRYPOINT_OBJ_HDRS}
159  )
160  target_compile_options(
161    ${objects_target_name}
162    BEFORE
163    PRIVATE
164      -fpie ${LLVM_CXX_STD_default} -ffreestanding
165  )
166  target_include_directories(
167    ${objects_target_name}
168    PRIVATE
169      ${LIBC_BUILD_DIR}/include
170      ${LIBC_SOURCE_DIR}
171      ${LIBC_BUILD_DIR}
172  )
173  get_fq_deps_list(fq_deps_list ${ADD_ENTRYPOINT_OBJ_DEPENDS})
174  add_dependencies(
175    ${objects_target_name}
176    libc.src.__support.common
177    ${fq_deps_list}
178  )
179
180  if(ADD_ENTRYPOINT_OBJ_COMPILE_OPTIONS)
181    target_compile_options(
182      ${objects_target_name}
183      PRIVATE ${ADD_ENTRYPOINT_OBJ_COMPILE_OPTIONS}
184    )
185  endif()
186
187  set(object_file_raw "${CMAKE_CURRENT_BINARY_DIR}/${target_name}_raw.o")
188  set(object_file "${CMAKE_CURRENT_BINARY_DIR}/${target_name}.o")
189
190  set(input_objects $<TARGET_OBJECTS:${objects_target_name}>)
191  add_custom_command(
192    OUTPUT ${object_file_raw}
193    DEPENDS ${input_objects}
194    COMMAND ${CMAKE_LINKER} -r ${input_objects} -o ${object_file_raw}
195  )
196
197  set(alias_attributes "0,function,global")
198  if(ADD_ENTRYPOINT_OBJ_REDIRECTED)
199    set(alias_attributes "${alias_attributes},hidden")
200  endif()
201
202  add_custom_command(
203    OUTPUT ${object_file}
204    # We llvm-objcopy here as GNU-binutils objcopy does not support the 'hidden' flag.
205    DEPENDS ${object_file_raw} ${llvm-objcopy}
206    COMMAND $<TARGET_FILE:llvm-objcopy> --add-symbol
207            "${entrypoint_name}=.llvm.libc.entrypoint.${entrypoint_name}:${alias_attributes}"
208            ${object_file_raw} ${object_file}
209  )
210
211  add_custom_target(
212    ${fq_target_name}
213    ALL
214    DEPENDS ${object_file}
215  )
216  set_target_properties(
217    ${fq_target_name}
218    PROPERTIES
219      "ENTRYPOINT_NAME" ${entrypoint_name}
220      "TARGET_TYPE" ${ENTRYPOINT_OBJ_TARGET_TYPE}
221      "OBJECT_FILE" "${object_file}"
222      "OBJECT_FILE_RAW" "${object_file_raw}"
223      "DEPS" "${fq_deps_list}"
224  )
225
226  if(LLVM_LIBC_ENABLE_LINTING)
227
228    # We only want a second invocation of clang-tidy to run
229    # restrict-system-libc-headers if the compiler-resource-dir was set in
230    # order to prevent false-positives due to a mismatch between the host
231    # compiler and the compiled clang-tidy.
232    if(COMPILER_RESOURCE_DIR)
233      # We run restrict-system-libc-headers with --system-headers to prevent
234      # transitive inclusion through compler provided headers.
235      set(restrict_system_headers_check_invocation
236        COMMAND $<TARGET_FILE:clang-tidy> --system-headers
237        --checks="-*,llvmlibc-restrict-system-libc-headers"
238        # We explicitly set the resource dir here to match the
239        # resource dir of the host compiler.
240        "--extra-arg=-resource-dir=${COMPILER_RESOURCE_DIR}"
241        --quiet
242        -p ${PROJECT_BINARY_DIR}
243        ${ADD_ENTRYPOINT_OBJ_SRCS}
244      )
245    else()
246      set(restrict_system_headers_check_invocation
247        COMMAND ${CMAKE_COMMAND} -E echo "Header file check skipped")
248    endif()
249
250    set(lint_timestamp "${CMAKE_CURRENT_BINARY_DIR}/.${target_name}.__lint_timestamp__")
251    add_custom_command(
252      OUTPUT ${lint_timestamp}
253      # --quiet is used to surpress warning statistics from clang-tidy like:
254      #     Suppressed X warnings (X in non-user code).
255      # There seems to be a bug in clang-tidy where by even with --quiet some
256      # messages from clang's own diagnostics engine leak through:
257      #     X warnings generated.
258      # Until this is fixed upstream, we use -fno-caret-diagnostics to surpress
259      # these.
260      COMMAND $<TARGET_FILE:clang-tidy>
261              "--extra-arg=-fno-caret-diagnostics" --quiet
262              # Path to directory containing compile_commands.json
263              -p ${PROJECT_BINARY_DIR}
264              ${ADD_ENTRYPOINT_OBJ_SRCS}
265      # See above: this might be a second invocation of clang-tidy depending on
266      # the conditions above.
267      ${restrict_system_headers_check_invocation}
268      # We have two options for running commands, add_custom_command and
269      # add_custom_target. We don't want to run the linter unless source files
270      # have changed. add_custom_target explicitly runs everytime therefore we
271      # use add_custom_command. This function requires an output file and since
272      # linting doesn't produce a file, we create a dummy file using a
273      # crossplatform touch.
274      COMMAND "${CMAKE_COMMAND}" -E touch ${lint_timestamp}
275      COMMENT "Linting... ${target_name}"
276      DEPENDS clang-tidy ${objects_target_name} ${ADD_ENTRYPOINT_OBJ_SRCS}
277      WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
278    )
279
280    add_custom_target(${fq_target_name}.__lint__
281      DEPENDS ${lint_timestamp})
282    add_dependencies(lint-libc ${fq_target_name}.__lint__)
283    add_dependencies(${fq_target_name} ${fq_target_name}.__lint__)
284  endif()
285
286endfunction(add_entrypoint_object)
287
288# Rule build a redirector object file.
289function(add_redirector_object target_name)
290  cmake_parse_arguments(
291    "REDIRECTOR_OBJECT"
292    "" # No optional arguments
293    "SRC" # The cpp file in which the redirector is defined.
294    "" # No multivalue arguments
295    ${ARGN}
296  )
297  if(NOT REDIRECTOR_OBJECT_SRC)
298    message(FATAL_ERROR "'add_redirector_object' rule requires SRC option listing one source file.")
299  endif()
300
301  add_library(
302    ${target_name}
303    OBJECT
304    ${REDIRECTOR_OBJECT_SRC}
305  )
306  target_compile_options(
307    ${target_name}
308    BEFORE PRIVATE -fPIC
309  )
310endfunction(add_redirector_object)
311