1function(collect_object_file_deps target result) 2 # NOTE: This function does add entrypoint targets to |result|. 3 # It is expected that the caller adds them separately. 4 set(all_deps "") 5 get_target_property(target_type ${target} "TARGET_TYPE") 6 if(NOT target_type) 7 return() 8 endif() 9 10 if(${target_type} STREQUAL ${OBJECT_LIBRARY_TARGET_TYPE}) 11 list(APPEND all_deps ${target}) 12 get_target_property(deps ${target} "DEPS") 13 foreach(dep IN LISTS deps) 14 collect_object_file_deps(${dep} dep_targets) 15 list(APPEND all_deps ${dep_targets}) 16 endforeach(dep) 17 list(REMOVE_DUPLICATES all_deps) 18 set(${result} ${all_deps} PARENT_SCOPE) 19 return() 20 endif() 21 22 if(${target_type} STREQUAL ${ENTRYPOINT_OBJ_TARGET_TYPE} OR 23 ${target_type} STREQUAL ${ENTRYPOINT_OBJ_VENDOR_TARGET_TYPE}) 24 set(entrypoint_target ${target}) 25 get_target_property(is_alias ${entrypoint_target} "IS_ALIAS") 26 if(is_alias) 27 get_target_property(aliasee ${entrypoint_target} "DEPS") 28 if(NOT aliasee) 29 message(FATAL_ERROR 30 "Entrypoint alias ${entrypoint_target} does not have an aliasee.") 31 endif() 32 set(entrypoint_target ${aliasee}) 33 endif() 34 get_target_property(deps ${target} "DEPS") 35 foreach(dep IN LISTS deps) 36 collect_object_file_deps(${dep} dep_targets) 37 list(APPEND all_deps ${dep_targets}) 38 endforeach(dep) 39 list(REMOVE_DUPLICATES all_deps) 40 set(${result} ${all_deps} PARENT_SCOPE) 41 return() 42 endif() 43 44 if(${target_type} STREQUAL ${ENTRYPOINT_EXT_TARGET_TYPE}) 45 # It is not possible to recursively extract deps of external dependencies. 46 # So, we just accumulate the direct dep and return. 47 get_target_property(deps ${target} "DEPS") 48 set(${result} ${deps} PARENT_SCOPE) 49 return() 50 endif() 51endfunction(collect_object_file_deps) 52 53function(get_all_object_file_deps result fq_deps_list) 54 set(all_deps "") 55 foreach(dep ${fq_deps_list}) 56 get_target_property(dep_type ${dep} "TARGET_TYPE") 57 if(NOT ((${dep_type} STREQUAL ${ENTRYPOINT_OBJ_TARGET_TYPE}) OR 58 (${dep_type} STREQUAL ${ENTRYPOINT_EXT_TARGET_TYPE}) OR 59 (${dep_type} STREQUAL ${ENTRYPOINT_OBJ_VENDOR_TARGET_TYPE}))) 60 message(FATAL_ERROR "Dependency '${dep}' of 'add_entrypoint_collection' is " 61 "not an 'add_entrypoint_object' or 'add_entrypoint_external' target.") 62 endif() 63 collect_object_file_deps(${dep} recursive_deps) 64 list(APPEND all_deps ${recursive_deps}) 65 # Add the entrypoint object target explicitly as collect_object_file_deps 66 # only collects object files from non-entrypoint targets. 67 if(${dep_type} STREQUAL ${ENTRYPOINT_OBJ_TARGET_TYPE} OR 68 ${dep_type} STREQUAL ${ENTRYPOINT_OBJ_VENDOR_TARGET_TYPE}) 69 set(entrypoint_target ${dep}) 70 get_target_property(is_alias ${entrypoint_target} "IS_ALIAS") 71 if(is_alias) 72 get_target_property(aliasee ${entrypoint_target} "DEPS") 73 if(NOT aliasee) 74 message(FATAL_ERROR 75 "Entrypoint alias ${entrypoint_target} does not have an aliasee.") 76 endif() 77 set(entrypoint_target ${aliasee}) 78 endif() 79 endif() 80 list(APPEND all_deps ${entrypoint_target}) 81 endforeach(dep) 82 list(REMOVE_DUPLICATES all_deps) 83 set(${result} ${all_deps} PARENT_SCOPE) 84endfunction() 85 86# A rule to build a library from a collection of entrypoint objects and bundle 87# it in a single LLVM-IR bitcode file. 88# Usage: 89# add_gpu_entrypoint_library( 90# DEPENDS <list of add_entrypoint_object targets> 91# ) 92function(add_bitcode_entrypoint_library target_name base_target_name) 93 cmake_parse_arguments( 94 "ENTRYPOINT_LIBRARY" 95 "" # No optional arguments 96 "" # No single value arguments 97 "DEPENDS" # Multi-value arguments 98 ${ARGN} 99 ) 100 if(NOT ENTRYPOINT_LIBRARY_DEPENDS) 101 message(FATAL_ERROR "'add_entrypoint_library' target requires a DEPENDS list " 102 "of 'add_entrypoint_object' targets.") 103 endif() 104 105 get_fq_deps_list(fq_deps_list ${ENTRYPOINT_LIBRARY_DEPENDS}) 106 get_all_object_file_deps(all_deps "${fq_deps_list}") 107 108 set(objects "") 109 foreach(dep IN LISTS all_deps) 110 set(object $<$<STREQUAL:$<TARGET_NAME_IF_EXISTS:${dep}>,${dep}>:$<TARGET_OBJECTS:${dep}>>) 111 list(APPEND objects ${object}) 112 endforeach() 113 114 add_executable(${target_name} ${objects}) 115 target_link_options(${target_name} PRIVATE 116 "-r" "-nostdlib" "-flto" "-Wl,--lto-emit-llvm") 117endfunction(add_bitcode_entrypoint_library) 118 119# A rule to build a library from a collection of entrypoint objects. 120# Usage: 121# add_entrypoint_library( 122# DEPENDS <list of add_entrypoint_object targets> 123# ) 124# 125# NOTE: If one wants an entrypoint to be available in a library, then they will 126# have to list the entrypoint target explicitly in the DEPENDS list. Implicit 127# entrypoint dependencies will not be added to the library. 128function(add_entrypoint_library target_name) 129 cmake_parse_arguments( 130 "ENTRYPOINT_LIBRARY" 131 "" # No optional arguments 132 "" # No single value arguments 133 "DEPENDS" # Multi-value arguments 134 ${ARGN} 135 ) 136 if(NOT ENTRYPOINT_LIBRARY_DEPENDS) 137 message(FATAL_ERROR "'add_entrypoint_library' target requires a DEPENDS list " 138 "of 'add_entrypoint_object' targets.") 139 endif() 140 141 get_fq_deps_list(fq_deps_list ${ENTRYPOINT_LIBRARY_DEPENDS}) 142 get_all_object_file_deps(all_deps "${fq_deps_list}") 143 144 set(objects "") 145 foreach(dep IN LISTS all_deps) 146 list(APPEND objects $<$<STREQUAL:$<TARGET_NAME_IF_EXISTS:${dep}>,${dep}>:$<TARGET_OBJECTS:${dep}>>) 147 endforeach(dep) 148 149 add_library( 150 ${target_name} 151 STATIC 152 ${objects} 153 ) 154 set_target_properties(${target_name} PROPERTIES ARCHIVE_OUTPUT_DIRECTORY ${LIBC_LIBRARY_DIR}) 155endfunction(add_entrypoint_library) 156 157# Rule to build a shared library of redirector objects. 158function(add_redirector_library target_name) 159 cmake_parse_arguments( 160 "REDIRECTOR_LIBRARY" 161 "" 162 "" 163 "DEPENDS" 164 ${ARGN} 165 ) 166 167 set(obj_files "") 168 foreach(dep IN LISTS REDIRECTOR_LIBRARY_DEPENDS) 169 # TODO: Ensure that each dep is actually a add_redirector_object target. 170 list(APPEND obj_files $<TARGET_OBJECTS:${dep}>) 171 endforeach(dep) 172 173 # TODO: Call the linker explicitly instead of calling the compiler driver to 174 # prevent DT_NEEDED on C++ runtime. 175 add_library( 176 ${target_name} 177 EXCLUDE_FROM_ALL 178 SHARED 179 ${obj_files} 180 ) 181 set_target_properties(${target_name} PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${LIBC_LIBRARY_DIR}) 182 target_link_libraries(${target_name} -nostdlib -lc -lm) 183 set_target_properties(${target_name} PROPERTIES LINKER_LANGUAGE "C") 184endfunction(add_redirector_library) 185 186set(HDR_LIBRARY_TARGET_TYPE "HDR_LIBRARY") 187 188# Internal function, used by `add_header_library`. 189function(create_header_library fq_target_name) 190 cmake_parse_arguments( 191 "ADD_HEADER" 192 "" # Optional arguments 193 "" # Single value arguments 194 "HDRS;DEPENDS;FLAGS;COMPILE_OPTIONS" # Multi-value arguments 195 ${ARGN} 196 ) 197 198 if(NOT ADD_HEADER_HDRS) 199 message(FATAL_ERROR "'add_header_library' target requires a HDRS list of .h files.") 200 endif() 201 202 if(SHOW_INTERMEDIATE_OBJECTS) 203 message(STATUS "Adding header library ${fq_target_name}") 204 if(${SHOW_INTERMEDIATE_OBJECTS} STREQUAL "DEPS") 205 foreach(dep IN LISTS ADD_HEADER_DEPENDS) 206 message(STATUS " ${fq_target_name} depends on ${dep}") 207 endforeach() 208 endif() 209 endif() 210 211 add_library(${fq_target_name} INTERFACE) 212 target_sources(${fq_target_name} INTERFACE ${ADD_HEADER_HDRS}) 213 if(ADD_HEADER_DEPENDS) 214 add_dependencies(${fq_target_name} ${ADD_HEADER_DEPENDS}) 215 216 # `*.__copied_hdr__` is created only to copy the header files to the target 217 # location, not to be linked against. 218 set(link_lib "") 219 foreach(dep ${ADD_HEADER_DEPENDS}) 220 if (NOT dep MATCHES "__copied_hdr__") 221 list(APPEND link_lib ${dep}) 222 endif() 223 endforeach() 224 225 target_link_libraries(${fq_target_name} INTERFACE ${link_lib}) 226 endif() 227 if(ADD_HEADER_COMPILE_OPTIONS) 228 target_compile_options(${fq_target_name} INTERFACE ${ADD_HEADER_COMPILE_OPTIONS}) 229 endif() 230 set_target_properties( 231 ${fq_target_name} 232 PROPERTIES 233 INTERFACE_FLAGS "${ADD_HEADER_FLAGS}" 234 TARGET_TYPE "${HDR_LIBRARY_TARGET_TYPE}" 235 DEPS "${ADD_HEADER_DEPENDS}" 236 FLAGS "${ADD_HEADER_FLAGS}" 237 ) 238endfunction(create_header_library) 239 240# Rule to add header only libraries. 241# Usage 242# add_header_library( 243# <target name> 244# HDRS <list of .h files part of the library> 245# DEPENDS <list of dependencies> 246# FLAGS <list of flags> 247# ) 248 249function(add_header_library target_name) 250 add_target_with_flags( 251 ${target_name} 252 CREATE_TARGET create_header_library 253 ${ARGN} 254 ) 255endfunction(add_header_library) 256