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# A rule to build a library from a collection of entrypoint objects.
36# Usage:
37#     add_entrypoint_library(
38#       DEPENDS <list of add_entrypoint_object targets>
39#     )
40#
41# NOTE: If one wants an entrypoint to be availabe in a library, then they will
42# have to list the entrypoint target explicitly in the DEPENDS list. Implicit
43# entrypoint dependencies will not be added to the library.
44function(add_entrypoint_library target_name)
45  cmake_parse_arguments(
46    "ENTRYPOINT_LIBRARY"
47    "" # No optional arguments
48    "" # No single value arguments
49    "DEPENDS" # Multi-value arguments
50    ${ARGN}
51  )
52  if(NOT ENTRYPOINT_LIBRARY_DEPENDS)
53    message(FATAL_ERROR "'add_entrypoint_library' target requires a DEPENDS list "
54                        "of 'add_entrypoint_object' targets.")
55  endif()
56
57  get_fq_deps_list(fq_deps_list ${ENTRYPOINT_LIBRARY_DEPENDS})
58  get_object_files_for_entrypoint_library(obj_list ${fq_deps_list})
59  foreach(dep IN LISTS fq_deps_list)
60    get_target_property(dep_type ${dep} "TARGET_TYPE")
61    if(NOT (${dep_type} STREQUAL ${ENTRYPOINT_OBJ_TARGET_TYPE}))
62      message(FATAL_ERROR "Dependency '${dep}' of 'add_entrypoint_collection' is "
63                          "not an 'add_entrypoint_object' target.")
64    endif()
65    get_target_property(objfile ${dep} "OBJECT_FILE")
66    list(APPEND obj_list ${objfile})
67  endforeach(dep)
68  list(REMOVE_DUPLICATES obj_list)
69
70  set(library_file "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_STATIC_LIBRARY_PREFIX}${target_name}${CMAKE_STATIC_LIBRARY_SUFFIX}")
71  add_custom_command(
72    OUTPUT ${library_file}
73    COMMAND ${CMAKE_AR} -r ${library_file} ${obj_list}
74    DEPENDS ${obj_list}
75  )
76  add_custom_target(
77    ${target_name}
78    ALL
79    DEPENDS ${library_file}
80  )
81endfunction(add_entrypoint_library)
82
83# Rule to build a shared library of redirector objects.
84function(add_redirector_library target_name)
85  cmake_parse_arguments(
86    "REDIRECTOR_LIBRARY"
87    ""
88    ""
89    "DEPENDS"
90    ${ARGN}
91  )
92
93  set(obj_files "")
94  foreach(dep IN LISTS REDIRECTOR_LIBRARY_DEPENDS)
95    # TODO: Ensure that each dep is actually a add_redirector_object target.
96    list(APPEND obj_files $<TARGET_OBJECTS:${dep}>)
97  endforeach(dep)
98
99  # TODO: Call the linker explicitly instead of calling the compiler driver to
100  # prevent DT_NEEDED on C++ runtime.
101  add_library(
102    ${target_name}
103    SHARED
104    ${obj_files}
105  )
106  set_target_properties(${target_name} PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
107
108  target_link_libraries(
109    ${target_name}
110    -nostdlib -lc -lm
111  )
112
113  set_target_properties(
114    ${target_name}
115    PROPERTIES
116      LINKER_LANGUAGE "C"
117  )
118endfunction(add_redirector_library)
119
120set(HDR_LIBRARY_TARGET_TYPE "HDR_LIBRARY")
121
122# Rule to add header only libraries.
123# Usage
124#    add_header_library(
125#      <target name>
126#      HDRS  <list of .h files part of the library>
127#      DEPENDS <list of dependencies>
128#    )
129function(add_header_library target_name)
130  cmake_parse_arguments(
131    "ADD_HEADER"
132    "" # No optional arguments
133    "" # No Single value arguments
134    "HDRS;DEPENDS" # Multi-value arguments
135    ${ARGN}
136  )
137
138  if(NOT ADD_HEADER_HDRS)
139    message(FATAL_ERROR "'add_header_library' target requires a HDRS list of .h files.")
140  endif()
141
142  get_fq_target_name(${target_name} fq_target_name)
143
144  set(FULL_HDR_PATHS "")
145  # TODO: Remove this foreach block when we can switch to the new
146  # version of the CMake policy CMP0076.
147  foreach(hdr IN LISTS ADD_HEADER_HDRS)
148    list(APPEND FULL_HDR_PATHS ${CMAKE_CURRENT_SOURCE_DIR}/${hdr})
149  endforeach()
150
151  set(interface_target_name "${fq_target_name}.__header_library__")
152
153  add_library(${interface_target_name} INTERFACE)
154  target_sources(${interface_target_name} INTERFACE ${FULL_HDR_PATHS})
155  get_fq_deps_list(fq_deps_list ${ADD_HEADER_DEPENDS})
156  if(ADD_HEADER_DEPENDS)
157    add_dependencies(${interface_target_name} ${fq_deps_list})
158  endif()
159
160  add_custom_target(${fq_target_name})
161  add_dependencies(${fq_target_name} ${interface_target_name})
162  set_target_properties(
163    ${fq_target_name}
164    PROPERTIES
165      "TARGET_TYPE" "${HDR_LIBRARY_TARGET_TYPE}"
166      "DEPS" "${fq_deps_list}"
167  )
168endfunction(add_header_library)
169