• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# This is a helper function and not a build rule. It is to be used by the
2# the "add_entrypoint_library" rule to generate the full list of object files
3# recursively produced by "add_object_library" targets upstream in the
4# dependency tree. This function traverses up through the
5# "add_entrypoint_object" targets but does not collect the object files
6# produced by them.
7# Usage:
8#   get_object_files_for_test(<result var> <target0> [<target1> ...])
9#
10#   targetN is either an "add_entrypoint_target" target or an
11#   "add_object_library" target.
12function(get_object_files_for_entrypoint_library result)
13  set(object_files "")
14  foreach(dep IN LISTS ARGN)
15    get_target_property(dep_type ${dep} "TARGET_TYPE")
16    if (NOT dep_type)
17      continue()
18    endif()
19
20    if(${dep_type} STREQUAL ${OBJECT_LIBRARY_TARGET_TYPE})
21      get_target_property(dep_object_files ${dep} "OBJECT_FILES")
22      if(dep_object_files)
23        list(APPEND object_files ${dep_object_files})
24      endif()
25    endif()
26
27    get_target_property(indirect_deps ${dep} "DEPS")
28    get_object_files_for_entrypoint_library(indirect_objfiles ${indirect_deps})
29    list(APPEND object_files ${indirect_objfiles})
30  endforeach(dep)
31  list(REMOVE_DUPLICATES object_files)
32  set(${result} ${object_files} PARENT_SCOPE)
33endfunction()
34
35# This is a helper function and not a build rule. Given an entrypoint object
36# target, it returns the object file produced by this target in |result|.
37# If the given entrypoint target is an alias, then it traverses up to the
38# aliasee to get the object file.
39function(get_entrypoint_object_file entrypoint_target result)
40  get_target_property(target_type ${entrypoint_target} "TARGET_TYPE")
41  if(NOT (${target_type} STREQUAL ${ENTRYPOINT_OBJ_TARGET_TYPE}))
42    message(FATAL_ERROR
43            "Expected an target added using `add_entrypoint_object` rule.")
44  endif()
45
46  get_target_property(objfile ${entrypoint_target} "OBJECT_FILE")
47  if(objfile)
48    set(${result} ${objfile} PARENT_SCOPE)
49    return()
50  endif()
51
52  # If the entrypoint is an alias, fetch the object file from the aliasee.
53  get_target_property(is_alias ${entrypoint_target} "IS_ALIAS")
54  if(is_alias)
55    get_target_property(aliasee ${entrypoint_target} "DEPS")
56    if(NOT aliasee)
57      message(FATAL_ERROR
58              "Entrypoint alias ${entrypoint_target} does not have an aliasee.")
59    endif()
60    get_entrypoint_object_file(${aliasee} objfile)
61    set(${result} ${objfile} PARENT_SCOPE)
62    return()
63  endif()
64
65  message(FATAL_ERROR
66          "Entrypoint ${entrypoint_target} does not produce an object file.")
67endfunction(get_entrypoint_object_file)
68
69# A rule to build a library from a collection of entrypoint objects.
70# Usage:
71#     add_entrypoint_library(
72#       DEPENDS <list of add_entrypoint_object targets>
73#     )
74#
75# NOTE: If one wants an entrypoint to be availabe in a library, then they will
76# have to list the entrypoint target explicitly in the DEPENDS list. Implicit
77# entrypoint dependencies will not be added to the library.
78function(add_entrypoint_library target_name)
79  cmake_parse_arguments(
80    "ENTRYPOINT_LIBRARY"
81    "" # No optional arguments
82    "" # No single value arguments
83    "DEPENDS" # Multi-value arguments
84    ${ARGN}
85  )
86  if(NOT ENTRYPOINT_LIBRARY_DEPENDS)
87    message(FATAL_ERROR "'add_entrypoint_library' target requires a DEPENDS list "
88                        "of 'add_entrypoint_object' targets.")
89  endif()
90
91  get_fq_deps_list(fq_deps_list ${ENTRYPOINT_LIBRARY_DEPENDS})
92  get_object_files_for_entrypoint_library(obj_list ${fq_deps_list})
93  foreach(dep IN LISTS fq_deps_list)
94    get_target_property(dep_type ${dep} "TARGET_TYPE")
95    if(NOT (${dep_type} STREQUAL ${ENTRYPOINT_OBJ_TARGET_TYPE}))
96      message(FATAL_ERROR "Dependency '${dep}' of 'add_entrypoint_collection' is "
97                          "not an 'add_entrypoint_object' target.")
98    endif()
99    get_entrypoint_object_file(${dep} objfile)
100    list(APPEND obj_list ${objfile})
101  endforeach(dep)
102  list(REMOVE_DUPLICATES obj_list)
103
104  set(library_file "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_STATIC_LIBRARY_PREFIX}${target_name}${CMAKE_STATIC_LIBRARY_SUFFIX}")
105  add_custom_command(
106    OUTPUT ${library_file}
107    COMMAND ${CMAKE_AR} -r ${library_file} ${obj_list}
108    DEPENDS ${obj_list}
109  )
110  add_custom_target(
111    ${target_name}
112    ALL
113    DEPENDS ${library_file}
114  )
115endfunction(add_entrypoint_library)
116
117# Rule to build a shared library of redirector objects.
118function(add_redirector_library target_name)
119  cmake_parse_arguments(
120    "REDIRECTOR_LIBRARY"
121    ""
122    ""
123    "DEPENDS"
124    ${ARGN}
125  )
126
127  set(obj_files "")
128  foreach(dep IN LISTS REDIRECTOR_LIBRARY_DEPENDS)
129    # TODO: Ensure that each dep is actually a add_redirector_object target.
130    list(APPEND obj_files $<TARGET_OBJECTS:${dep}>)
131  endforeach(dep)
132
133  # TODO: Call the linker explicitly instead of calling the compiler driver to
134  # prevent DT_NEEDED on C++ runtime.
135  add_library(
136    ${target_name}
137    SHARED
138    ${obj_files}
139  )
140  set_target_properties(${target_name} PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
141
142  target_link_libraries(
143    ${target_name}
144    -nostdlib -lc -lm
145  )
146
147  set_target_properties(
148    ${target_name}
149    PROPERTIES
150      LINKER_LANGUAGE "C"
151  )
152endfunction(add_redirector_library)
153
154set(HDR_LIBRARY_TARGET_TYPE "HDR_LIBRARY")
155
156# Rule to add header only libraries.
157# Usage
158#    add_header_library(
159#      <target name>
160#      HDRS  <list of .h files part of the library>
161#      DEPENDS <list of dependencies>
162#    )
163function(add_header_library target_name)
164  cmake_parse_arguments(
165    "ADD_HEADER"
166    "" # No optional arguments
167    "" # No Single value arguments
168    "HDRS;DEPENDS" # Multi-value arguments
169    ${ARGN}
170  )
171
172  if(NOT ADD_HEADER_HDRS)
173    message(FATAL_ERROR "'add_header_library' target requires a HDRS list of .h files.")
174  endif()
175
176  get_fq_target_name(${target_name} fq_target_name)
177
178  set(FULL_HDR_PATHS "")
179  # TODO: Remove this foreach block when we can switch to the new
180  # version of the CMake policy CMP0076.
181  foreach(hdr IN LISTS ADD_HEADER_HDRS)
182    list(APPEND FULL_HDR_PATHS ${CMAKE_CURRENT_SOURCE_DIR}/${hdr})
183  endforeach()
184
185  set(interface_target_name "${fq_target_name}.__header_library__")
186
187  add_library(${interface_target_name} INTERFACE)
188  target_sources(${interface_target_name} INTERFACE ${FULL_HDR_PATHS})
189  get_fq_deps_list(fq_deps_list ${ADD_HEADER_DEPENDS})
190  if(ADD_HEADER_DEPENDS)
191    add_dependencies(${interface_target_name} ${fq_deps_list})
192  endif()
193
194  add_custom_target(${fq_target_name})
195  add_dependencies(${fq_target_name} ${interface_target_name})
196  set_target_properties(
197    ${fq_target_name}
198    PROPERTIES
199      "TARGET_TYPE" "${HDR_LIBRARY_TARGET_TYPE}"
200      "DEPS" "${fq_deps_list}"
201  )
202endfunction(add_header_library)
203