• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Copyright 2018 The Android Open Source Project
2#
3# Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
4# the License. You may obtain a copy of the License at
5#
6# http://www.apache.org/licenses/LICENSE-2.0
7#
8# Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an
9# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
10# specific language governing permissions and limitations under the License.
11# This contains a set of functions to make working with different targets a lot easier. The idea is that you can now set
12# properties that define your lib/executable through variables that follow the following naming conventions
13#
14if(INCLUDE_ANDROID_CMAKE)
15  return()
16endif()
17
18set(INCLUDE_ANDROID_CMAKE 1)
19
20# We want to make sure all the cross targets end up in a unique location
21set(ANDROID_CROSS_BUILD_DIRECTORY ${CMAKE_BINARY_DIR}/build/${ANDROID_HOST_TAG})
22
23# Checks to make sure the TAG is valid.
24function(_check_target_tag TAG)
25  set(VALID_TARGETS
26      windows
27      windows_msvc-x86_64
28      linux-x86_64
29      linux-aarch64
30      darwin-x86_64
31      all
32      Clang)
33  if(NOT (TAG IN_LIST VALID_TARGETS))
34    message(
35      FATAL_ERROR
36        "The target ${TAG} does not exist, has to be one of: ${VALID_TARGETS}")
37  endif()
38endfunction()
39
40# Cross compiles the given cmake project if needed.
41#
42# EXE the name of the target we are interested in. This is the main build
43# product you want to use. SOURCE the location of the CMakeList.txt describing
44# the project. OUT_PATH Name of the variable that will contain the resulting
45# executable.
46function(android_compile_for_host EXE SOURCE OUT_PATH)
47  if(NOT CROSSCOMPILE)
48    # We can add this project without any translation..
49    if(NOT TARGET ${EXE})
50      message(STATUS "Adding ${EXE} as subproject, not cross compiling.")
51      add_subdirectory(${SOURCE} ${EXE}_ext)
52    endif()
53    set(${OUT_PATH} "$<TARGET_FILE:${EXE}>" PARENT_SCOPE)
54  else()
55    include(ExternalProject)
56
57    # If we are cross compiling we will need to build it for our actual OS we
58    # are currently running on.
59    get_filename_component(
60      BUILD_PRODUCT
61      ${ANDROID_CROSS_BUILD_DIRECTORY}/${EXE}_ext_cross/src/${EXE}_ext_cross-build/${EXE}
62      ABSOLUTE)
63    if(NOT TARGET ${EXE}_ext_cross)
64      message(STATUS "Cross compiling ${EXE} for host ${ANDROID_HOST_TAG}")
65      externalproject_add(
66        ${EXE}_ext_cross
67        PREFIX ${ANDROID_CROSS_BUILD_DIRECTORY}/${EXE}_ext_cross
68        DOWNLOAD_COMMAND ""
69        SOURCE_DIR ${SOURCE}
70        CMAKE_ARGS
71          "-DCMAKE_TOOLCHAIN_FILE=${ANDROID_QEMU2_TOP_DIR}/android/build/cmake/toolchain-${ANDROID_HOST_TAG}.cmake"
72        BUILD_BYPRODUCTS ${BUILD_PRODUCT}
73        TEST_BEFORE_INSTALL True
74        INSTALL_COMMAND "")
75    endif()
76    set(${OUT_PATH} ${BUILD_PRODUCT} PARENT_SCOPE)
77  endif()
78endfunction()
79
80# ~~~
81# Enable the compilation of .asm files using nasm. This will include the nasm project if needed to compile the assembly
82# files.
83#
84# The following parameters are accepted
85#
86# ``TARGET`` The library target to generate.
87# ``INCLUDES`` Optional list of include paths to pass to nasm
88# ``SOURCES`` List of source files to be compiled.
89#
90# For example:
91#    android_nasm_compile(TARGET foo_asm INCLUDES /tmp/foo /tmp/more_foo SOURCES /tmp/bar /tmp/z)
92#
93# nasm will be compiled for the HOST platform if needed.
94# ~~~
95function(android_nasm_compile)
96  _register_target(${ARGN})
97  # Parse arguments
98  set(options)
99  set(oneValueArgs TARGET)
100  set(multiValueArgs INCLUDES SOURCES)
101  cmake_parse_arguments(android_nasm_compile "${options}" "${oneValueArgs}"
102                        "${multiValueArgs}" ${ARGN})
103
104  # Configure nasm
105  android_compile_for_host(
106    nasm ${ANDROID_QEMU2_TOP_DIR}/android/third_party/nasm nasm_EXECUTABLE)
107
108  # Setup the includes.
109  set(LIBNAME ${android_nasm_compile_TARGET})
110  set(ASM_INC "")
111  foreach(INCLUDE ${android_nasm_compile_INCLUDES})
112    set(ASM_INC ${ASM_INC} -I ${INCLUDE})
113  endforeach()
114
115  # Configure the nasm compile command.
116  foreach(asm ${REGISTERED_SRC})
117    get_filename_component(asm_base ${asm} NAME_WE)
118    set(DST ${CMAKE_CURRENT_BINARY_DIR}/${asm_base}.o)
119    add_custom_command(
120      OUTPUT ${DST}
121      COMMAND ${nasm_EXECUTABLE} -f ${ANDROID_ASM_TYPE} -o ${DST} ${asm}
122              ${ASM_INC}
123      WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
124      VERBATIM
125      DEPENDS ${nasm_EXECUTABLE} ${asm})
126    list(APPEND ${LIBNAME}_asm_o ${DST})
127  endforeach()
128
129  # Make the library available
130  add_library(${LIBNAME} ${${LIBNAME}_asm_o})
131  set_target_properties(${LIBNAME} PROPERTIES LINKER_LANGUAGE CXX)
132endfunction()
133
134# This function is the same as target_compile_definitions
135# (https://cmake.org/cmake/help/v3.5/command/target_compile_definitions.html)
136# The only difference is that the definitions will only be applied if the OS
137# parameter matches the ANDROID_TARGET_TAG or compiler variable.
138function(android_target_compile_definitions TGT OS MODIFIER ITEMS)
139  _check_target_tag(${OS})
140  if(ANDROID_TARGET_TAG MATCHES "${OS}.*" OR OS STREQUAL "all"
141     OR OS MATCHES "${CMAKE_CXX_COMPILER_ID}")
142    target_compile_definitions(${TGT} ${MODIFIER} ${ITEMS})
143    foreach(DEF ${ARGN})
144      target_compile_definitions(${TGT} ${MODIFIER} ${DEF})
145    endforeach()
146  endif()
147endfunction()
148
149# This function is the same as target_link_libraries
150# (https://cmake.org/cmake/help/v3.5/command/target_link_libraries.html) T he
151# only difference is that the definitions will only be applied if the OS
152# parameter matches the ANDROID_TARGET_TAG or Compiler variable.
153function(android_target_link_libraries TGT OS MODIFIER ITEMS)
154  if(ARGC GREATER "49")
155    message(
156      FATAL_ERROR
157        "Currently cannot link more than 49 dependecies due to some weirdness with calling target_link_libs"
158    )
159  endif()
160  _check_target_tag(${OS})
161  if(ANDROID_TARGET_TAG MATCHES "${OS}.*" OR OS STREQUAL "all"
162     OR OS MATCHES "${CMAKE_CXX_COMPILER_ID}")
163    # HACK ATTACK! We cannot properly expand unknown linker args as they are
164    # treated in a magical fashion. Some arguments need to be "grouped" together
165    # somehow (for example optimized;lib) since we cannot resolve this properly
166    # we just pass on the individual arguments..
167    # cmake-format: off
168    target_link_libraries(${TGT} ${MODIFIER} ${ARGV3} ${ARGV4} ${ARGV5} ${ARGV6} ${ARGV7} ${ARGV8} ${ARGV9}
169                          ${ARGV10} ${ARGV11} ${ARGV12} ${ARGV13} ${ARGV14} ${ARGV15} ${ARGV16} ${ARGV17} ${ARGV18} ${ARGV19}
170                          ${ARGV20} ${ARGV21} ${ARGV22} ${ARGV23} ${ARGV24} ${ARGV25} ${ARGV26} ${ARGV27} ${ARGV28} ${ARGV29}
171                          ${ARGV30} ${ARGV31} ${ARGV32} ${ARGV33} ${ARGV34} ${ARGV35} ${ARGV36} ${ARGV37} ${ARGV38} ${ARGV39}
172                          ${ARGV40} ${ARGV41} ${ARGV42} ${ARGV43} ${ARGV44} ${ARGV45} ${ARGV46} ${ARGV47} ${ARGV48} ${ARGV49})
173    # cmake-format: on
174  endif()
175endfunction()
176
177# This function is the same as target_include_directories
178# (https://cmake.org/cmake/help/v3.5/command/target_include_directories.html)
179# The only difference is that the definitions will only be applied if the OS
180# parameter matches the ANDROID_TARGET_TAG variable.
181function(android_target_include_directories TGT OS MODIFIER ITEMS)
182  _check_target_tag(${OS})
183  if(ANDROID_TARGET_TAG MATCHES "${OS}.*" OR OS STREQUAL "all"
184     OR OS MATCHES "${CMAKE_CXX_COMPILER_ID}")
185    target_include_directories(${TGT} ${MODIFIER} ${ITEMS})
186    foreach(DIR ${ARGN})
187      target_include_directories(${TGT} ${MODIFIER} ${DIR})
188    endforeach()
189  endif()
190endfunction()
191
192# This function is the same as target_compile_options
193# (https://cmake.org/cmake/help/v3.5/command/target_compile_options.html) The
194# only difference is that the definitions will only be applied if the OS
195# parameter matches the ANDROID_TARGET_TAG variable.
196function(android_target_compile_options TGT OS MODIFIER ITEMS)
197  _check_target_tag(${OS})
198  if(ANDROID_TARGET_TAG MATCHES "${OS}.*" OR OS STREQUAL "all"
199     OR OS MATCHES "${CMAKE_CXX_COMPILER_ID}")
200    target_compile_options(${TGT} ${MODIFIER} "${ITEMS};${ARGN}")
201  endif()
202endfunction()
203
204# ~~~
205# Registers the given target, by calculating the source set and setting licensens.
206#
207# ``TARGET``  The library/executable target. For example emulatory-libyuv
208# ``LIBNAME`` Public library name, this is how it is known in the world. For example libyuv.
209# ``SOURCES`` List of source files to be compiled, part of every target.
210# ``LINUX``   List of source files to be compiled if the current target is LINUX_X86_64
211# ``DARWIN``  List of source files to be compiled if the current target is DARWIN_X86_64
212# ``WINDOWS`` List of source files to be compiled if the current target is WINDOWS_MSVC_X86_64
213# ``MSVC``    List of source files to be compiled if the current target is  WINDOWS_MSVC_X86_64
214# ``URL``     URL where the source code can be found.
215# ``REPO``    Internal location where the, where the notice can be found.
216# ``LICENSE`` SPDX License identifier.
217# ``NOTICE``  Location where the NOTICE can be found
218# ~~~
219function(_register_target)
220  set(options NODISTRIBUTE)
221  set(oneValueArgs TARGET LICENSE LIBNAME REPO URL NOTICE)
222  set(multiValueArgs SRC LINUX MSVC WINDOWS DARWIN)
223  cmake_parse_arguments(build "${options}" "${oneValueArgs}"
224                        "${multiValueArgs}" ${ARGN})
225  if(NOT DEFINED build_TARGET)
226    message(FATAL_ERROR "Undefined target for library.")
227  endif()
228
229  set(src ${build_SRC})
230  if(LINUX AND build_LINUX)
231    list(APPEND src ${build_LINUX})
232  elseif(DARWIN_X86_64 AND build_DARWIN)
233    list(APPEND src ${build_DARWIN})
234  elseif(WINDOWS_MSVC_X86_64 AND (build_MSVC OR build_WINDOWS))
235    list(APPEND src ${build_MSVC} ${build_WINDOWS})
236  endif()
237
238  set(REGISTERED_SRC ${src} PARENT_SCOPE)
239  if(build_NODISTRIBUTE)
240    return()
241  endif()
242
243  if(NOT DEFINED build_LIBNAME)
244    set(build_LIBNAME ${build_TARGET})
245  endif()
246
247  if(NOT DEFINED build_LICENSE)
248    message(
249      FATAL_ERROR
250        "You must set a license for ${build_TARGET}, or declare NODISTRIBUTE")
251  endif()
252
253  if(NOT DEFINED build_NOTICE)
254    set(build_URL
255        "https://android.googlesource.com/platform/external/qemu.git/+/refs/heads/emu-master-dev"
256    )
257    set(build_REPO "INTERNAL")
258    set(build_NOTICE "REPO/LICENSES/LICENSE.APACHE2")
259  endif()
260
261  if(NOT DEFINED build_URL OR NOT DEFINED build_REPO OR NOT DEFINED
262                                                        build_NOTICE)
263    message(
264      FATAL_ERROR
265        "You must set a notice/url/repo for ${build_TARGET}, or declare NODISTRIBUTE"
266    )
267  endif()
268  if(DEFINED build_NOTICE AND NOT ${build_NODISTRIBUTE})
269    string(REPLACE "REPO" "${build_URL}" REMOTE_LICENSE ${build_NOTICE})
270    string(REPLACE "REPO" "${build_REPO}" LOCAL_LICENSE ${build_NOTICE})
271    android_license(
272      TARGET ${build_TARGET} URL ${build_URL} LIBNAME ${build_LIBNAME}
273      SPDX ${build_LICENSE} LICENSE ${REMOTE_LICENSE} LOCAL ${LOCAL_LICENSE})
274  endif()
275endfunction()
276
277# ~~~
278# Registers the given library, by calculating the source set and setting licensens.
279#
280# ``SHARED``  Option indicating that this is a shared library.
281# ``TARGET``  The library/executable target. For example emulatory-libyuv
282# ``LIBNAME`` Public library name, this is how it is known in the world. For example libyuv.
283# ``SOURCES`` List of source files to be compiled, part of every target.
284# ``LINUX``   List of source files to be compiled if the current target is LINUX_X86_64
285# ``DARWIN``  List of source files to be compiled if the current target is DARWIN_X86_64
286# ``WINDOWS`` List of source files to be compiled if the current target is WINDOWS_MSVC_X86_64
287# ``MSVC``    List of source files to be compiled if the current target is  WINDOWS_MSVC_X86_64
288# ``URL``     URL where the source code can be found.
289# ``REPO``    Internal location where the, where the notice can be found.
290# ``LICENSE`` SPDX License identifier.
291# ``NOTICE``  Location where the NOTICE can be found
292# ~~~
293function(android_add_library)
294  _register_target(${ARGN})
295  set(options SHARED)
296  set(oneValueArgs TARGET)
297  set(multiValueArgs "")
298  cmake_parse_arguments(build "${options}" "${oneValueArgs}"
299                        "${multiValueArgs}" ${ARGN})
300  if(${build_SHARED})
301    add_library(${build_TARGET} SHARED ${REGISTERED_SRC})
302  else()
303    add_library(${build_TARGET} ${REGISTERED_SRC})
304  endif()
305
306  if(WINDOWS_MSVC_X86_64 AND NOT ${build_TARGET} STREQUAL "msvc-posix-compat")
307    target_link_libraries(${build_TARGET} PRIVATE msvc-posix-compat)
308  endif()
309  android_clang_tidy(${build_TARGET})
310  # Clang on mac os does not get properly recognized by cmake
311  if (NOT DARWIN_X86_64)
312      target_compile_features(${build_TARGET} PRIVATE cxx_std_17)
313  endif()
314
315  if(${build_SHARED})
316    # We don't want cmake to binplace the shared libraries into the bin
317    # directory As this can make them show up in unexpected places!
318    if(ANDROID_TARGET_TAG MATCHES "windows.*")
319      set_target_properties(
320        ${build_TARGET} PROPERTIES RUNTIME_OUTPUT_DIRECTORY
321                                   ${CMAKE_LIBRARY_OUTPUT_DIRECTORY})
322    endif()
323    if(CROSSCOMPILE AND WINDOWS_MSVC_X86_64)
324      # For windows-msvc build (on linux), this generates a dll and a lib
325      # (import library) file. The files are being placed at
326      # ${CMAKE_RUNTIME_OUTPUT_DIRECTORY} which is correct for the dll, but the
327      # lib file needs to be in the ${CMAKE_ARCHIVE_OUTPUT_DIRECTORY} or we
328      # can't link to it. Most windows compilers, including clang, don't allow
329      # you to directly link to a dll (unlike mingw), and instead, need to link
330      # to it's import library.
331      #
332      # Another headache: it seems we attach a prefix to some of our shared
333      # libraries, which make cmake unable to locate the import library later on
334      # to whoever tries to link to it (e.g. OpenglRender -> lib64OpenglRender),
335      # as it will look for an import library by <target_library_name>.lib. We
336      # just symlink things to make it work.
337      add_custom_command(
338        TARGET ${build_TARGET}
339        POST_BUILD
340        COMMAND
341          ${CMAKE_COMMAND} -E create_symlink
342          $<TARGET_FILE_DIR:${build_TARGET}>/${CMAKE_SHARED_LIBRARY_PREFIX}$<TARGET_LINKER_FILE_NAME:${build_TARGET}>
343          ${CMAKE_ARCHIVE_OUTPUT_DIRECTORY}/$<TARGET_LINKER_FILE_NAME:${build_TARGET}>
344        COMMENT
345          "ln -sf $<TARGET_FILE_DIR:${build_TARGET}>/${CMAKE_ARCHIVE_OUTPUT_DIRECTORY}/$<TARGET_LINKER_FILE_NAME:${build_TARGET}> ${CMAKE_SHARED_LIBRARY_PREFIX}$<TARGET_LINKER_FILE_NAME:${build_TARGET}>"
346      )
347    endif()
348  endif()
349endfunction()
350
351# Discovers all the targets that are registered by this subdirectory.
352#
353# result: The variable containing all the targets defined by this project
354# subdir: The directory of interest
355function(android_discover_targets result subdir)
356  if(CMAKE_VERSION VERSION_LESS "3.7.0")
357    message(
358      FATAL_ERROR
359        "This function cannot be used by older cmake versions (${CMAKE_VERSION}<3.7.0)"
360    )
361  endif()
362  get_directory_property(subdirs DIRECTORY "${subdir}" SUBDIRECTORIES)
363  foreach(subdir IN LISTS subdirs)
364    android_discover_targets(${result} "${subdir}")
365  endforeach()
366  get_property(targets_in_dir DIRECTORY "${subdir}"
367               PROPERTY BUILDSYSTEM_TARGETS)
368  set(${result} ${${result}} ${targets_in_dir} PARENT_SCOPE)
369endfunction()
370
371# Adds an external project, transforming all external "executables" to include
372# the runtime properties. On linux for example this will set the rpath to find
373# libc++
374#
375# NOTE: This function requires CMake version > 3.7
376function(android_add_subdirectory external_directory name)
377  get_filename_component(abs_dir ${external_directory} ABSOLUTE)
378  add_subdirectory(${abs_dir} ${name})
379  android_discover_targets(targets ${abs_dir})
380  foreach(target IN LISTS targets)
381    get_target_property(tgt_type ${target} TYPE)
382    if(tgt_type STREQUAL "EXECUTABLE")
383      android_target_properties(${target} all "${RUNTIME_OS_PROPERTIES}")
384    endif()
385  endforeach()
386endfunction()
387
388function(android_clang_tidy name)
389  if(${name} IN_LIST OPTION_CLANG_TIDY)
390    message(STATUS "Tidying ${name}")
391    if(OPTION_CLANG_TIDY_FIX)
392      message(STATUS " ===> Applying fixes to ${name}")
393    endif()
394    set_target_properties(${name} PROPERTIES CXX_CLANG_TIDY "${DO_CLANG_TIDY}")
395  endif()
396endfunction()
397
398# ~~~
399# Registers the given library as an interface by calculating the source set and setting licensens.
400# An INTERFACE library target does not directly create build output, though it may have properties
401# set on it and it may be installed, exported and imported.
402#
403# ``TARGET``  The library/executable target. For example emulatory-libyuv
404# ``LIBNAME`` Public library name, this is how it is known in the world. For example libyuv.
405# ``URL``     URL where the source code can be found.
406# ``REPO``    Internal location where the, where the notice can be found.
407# ``LICENSE`` SPDX License identifier.
408# ``NOTICE``  Location where the NOTICE can be found
409# ~~~
410function(android_add_interface)
411  _register_target(${ARGN})
412  set(options "")
413  set(oneValueArgs TARGET)
414  set(multiValueArgs "")
415  cmake_parse_arguments(build "${options}" "${oneValueArgs}"
416                        "${multiValueArgs}" ${ARGN})
417  add_library(${build_TARGET} INTERFACE)
418endfunction()
419
420define_property(
421  GLOBAL PROPERTY LICENSES_LST BRIEF_DOCS "Global list of license definitions"
422  FULL_DOCS "Global list of license definitions")
423define_property(
424  GLOBAL PROPERTY INSTALL_TARGETS_LST
425  BRIEF_DOCS "GLobal list of targets that are installed."
426  FULL_DOCS "GLobal list of targets that are installed.")
427set_property(GLOBAL PROPERTY LICENSES_LST " ")
428set_property(GLOBAL PROPERTY INSTALL_TARGETS_LST " ")
429
430# ~~~
431# ! android_license: Registers the given license, ands adds it to LICENSES_LST for post processing !
432#
433# ``LIBNAME`` The name of the library, this is how it is usually known in the world.
434#             for example: libpng
435# ``URL``     The location where the source code for this library can be found.
436# ``TARGET``  List of targets that are part of the named library. For example crypto;ssl
437# ``SPDX``    The spdx license identifier. (See https://spdx.org/)
438# ``LOCAL``   Path to the NOTICE/LICENSE file.
439# ``LICENSE`` Url to the actual license file.
440# ~~
441function(android_license)
442  # Parse arguments
443  set(options)
444  set(oneValueArgs LIBNAME URL SPDX LICENSE LOCAL)
445  set(multiValueArgs TARGET)
446  cmake_parse_arguments(args "${options}" "${oneValueArgs}" "${multiValueArgs}"
447                        ${ARGN})
448  string(REPLACE "//" "/" URL "${args_URL}")
449  string(REPLACE ":/" "://" URL "${URL}")
450  string(REPLACE "//" "/" LICENSE "${args_LICENSE}")
451  string(REPLACE ":/" "://" LICENSE "${LICENSE}")
452  set_property(
453    GLOBAL APPEND
454    PROPERTY
455      LICENSES_LST
456      "${args_TARGET}|${args_LIBNAME}|${URL}|${args_SPDX}|${LICENSE}|${args_LOCAL}\n"
457  )
458endfunction()
459
460# ~~~
461# Finalize all licenses:
462#
463# 1. Writes out all license related information to a file.
464# 2. Invokes the python license validator.
465# ~~~
466function(finalize_all_licenses)
467  android_discover_targets(ALL_TARGETS ${ANDROID_QEMU2_TOP_DIR})
468  get_property(LICENSES GLOBAL PROPERTY LICENSES_LST)
469  get_property(TARGETS GLOBAL PROPERTY INSTALL_TARGETS_LST)
470  file(REMOVE ${CMAKE_BINARY_DIR}/TARGET_DEPS.LST)
471  file(WRITE ${CMAKE_BINARY_DIR}/LICENSES.LST "${LICENSES}")
472  file(WRITE ${CMAKE_BINARY_DIR}/INSTALL_TARGETS.LST "${TARGETS}")
473  foreach(tgt ${ALL_TARGETS})
474    get_target_property(target_type "${tgt}" TYPE)
475    set(DEPS "")
476    if(NOT target_type STREQUAL "INTERFACE_LIBRARY")
477      get_target_property(DEPS ${tgt} LINK_LIBRARIES)
478    endif()
479    file(APPEND ${CMAKE_BINARY_DIR}/TARGET_DEPS.LST
480         ";${tgt}|${target_type}|${DEPS}\n")
481  endforeach()
482
483  execute_process(
484    COMMAND "python" "android/build/python/aemu/licensing.py"
485            "${PROJECT_BINARY_DIR}" WORKING_DIRECTORY ${ANDROID_QEMU2_TOP_DIR}
486    RESULT_VARIABLE LICENSE_RES OUTPUT_VARIABLE STD_OUT ERROR_VARIABLE STD_ERR)
487  if(NOT "${LICENSE_RES}" STREQUAL "0")
488    message(
489      FATAL_ERROR
490        "Unable to validate licenses, out: ${STD_OUT}, err: ${STD_ERR}")
491  endif()
492endfunction()
493
494# Creates the dependency
495function(android_install_license tgt targetname)
496  set_property(GLOBAL APPEND PROPERTY INSTALL_TARGETS_LST
497                                      "${tgt}|${targetname}\n")
498endfunction()
499
500function(android_add_default_test_properties name)
501  # Configure the test to run with asan..
502  file(READ "${ANDROID_QEMU2_TOP_DIR}/android/asan_overrides" ASAN_OVERRIDES)
503  set_property(TEST ${name} PROPERTY ENVIRONMENT
504                                     "ASAN_OPTIONS=${ASAN_OVERRIDES}")
505  set_property(
506    TEST ${name} APPEND
507    PROPERTY ENVIRONMENT
508             "LLVM_PROFILE_FILE=$<TARGET_FILE_NAME:${name}>.profraw")
509  set_property(
510    TEST ${name} APPEND
511    PROPERTY ENVIRONMENT "ASAN_SYMBOLIZER_PATH=${ANDROID_LLVM_SYMBOLIZER}")
512  set_property(TEST ${name} PROPERTY TIMEOUT 600)
513
514  if(WINDOWS_MSVC_X86_64)
515    # Let's include the .dll path for our test runner
516    string(
517      REPLACE
518        "/"
519        "\\"
520        WIN_PATH
521        "${CMAKE_LIBRARY_OUTPUT_DIRECTORY};${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/gles_swiftshader;${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/qt/lib;$ENV{PATH}"
522    )
523    string(
524      REPLACE
525        ";"
526        "\;"
527        WIN_PATH
528        "${WIN_PATH}"
529    )
530    set_property(TEST ${name} APPEND PROPERTY ENVIRONMENT "PATH=${WIN_PATH}")
531  endif()
532endfunction()
533
534# ~~~
535# Adds a test target. It will create and register the test with the given name.
536# Test targets are marked as NODISTRIBUTE and hence cannot be installed
537#
538# ``TARGET``  The library/executable target. For example emulatory-libyuv
539# ``SOURCES`` List of source files to be compiled, part of every target.
540# ``LINUX``   List of source files to be compiled if the current target is LINUX_X86_64
541# ``DARWIN``  List of source files to be compiled if the current target is DARWIN_X86_64
542# ``WINDOWS`` List of source files to be compiled if the current target is WINDOWS_MSVC_X86_64
543# ``MSVC``    List of source files to be compiled if the current target is  WINDOWS_MSVC_X86_64
544# ~~~
545function(android_add_test)
546  android_add_executable(${ARGN} NODISTRIBUTE)
547
548  set(options "")
549  set(oneValueArgs TARGET)
550  set(multiValueArgs "")
551  cmake_parse_arguments(build "${options}" "${oneValueArgs}"
552                        "${multiValueArgs}" ${ARGN})
553
554  add_test(
555    NAME ${build_TARGET}
556    COMMAND
557      $<TARGET_FILE:${build_TARGET}>
558      --gtest_output=xml:$<TARGET_FILE_NAME:${build_TARGET}>.xml
559      --gtest_catch_exceptions=0
560    WORKING_DIRECTORY $<TARGET_FILE_DIR:${build_TARGET}>)
561
562  android_install_as_debug_info(${build_TARGET})
563  # Let's not optimize our tests.
564  target_compile_options(${build_TARGET} PRIVATE -O0)
565
566  android_add_default_test_properties(${build_TARGET})
567endfunction()
568
569# Installs the given target into ${DBG_INFO}/tests/ directory.. This is mainly
570# there so we can preserve it as part of our automated builds.
571function(android_install_as_debug_info name)
572  if(NOT DEFINED DBG_INFO)
573    # Ignore when cross-compiling withouth dbg_info available.
574    return()
575  endif()
576
577  # TODO(jansene): Would be nice if we could make this part of install.
578  add_custom_command(
579    TARGET ${name} POST_BUILD
580    COMMAND ${CMAKE_COMMAND} -E copy_if_different $<TARGET_FILE:${name}>
581            ${DBG_INFO}/tests/$<TARGET_FILE_NAME:${name}>)
582endfunction()
583
584# ~~~
585# Adds the given executable, by calculating the source set and registering the license
586#
587# ``SHARED``  Option indicating that this is a shared library.
588# ``NODISTRIBUTE`` Option indicating that we will not distribute this.
589# ``INSTALL`` Location where this executable should be installed if needed.
590# ``TARGET``  The library/executable target. For example emulatory-libyuv
591# ``LIBNAME`` Public library name, this is how it is known in the world. For example libyuv.
592# ``SOURCES`` List of source files to be compiled, part of every target.
593# ``LINUX``   List of source files to be compiled if the current target is LINUX_X86_64
594# ``DARWIN``  List of source files to be compiled if the current target is DARWIN_X86_64
595# ``WINDOWS`` List of source files to be compiled if the current target is WINDOWS_MSVC_X86_64
596# ``MSVC``    List of source files to be compiled if the current target is WINDOWS_MSVC_X86_64
597# ``URL``     URL where the source code can be found.
598# ``REPO``    Internal location where the notice can be found.
599# ``LICENSE`` SPDX License identifier.
600# ``NOTICE``  Location where the NOTICE can be found relative to the source URL. Should be written
601#             as REPO/path/to/license.
602# ~~~
603function(android_add_executable)
604  _register_target(${ARGN})
605  set(options "")
606  set(oneValueArgs TARGET INSTALL)
607  set(multiValueArgs "")
608  cmake_parse_arguments(build "${options}" "${oneValueArgs}"
609                        "${multiValueArgs}" ${ARGN})
610
611  add_executable(${build_TARGET} ${REGISTERED_SRC})
612  # Clang on mac os does not get properly recognized by cmake
613  if (NOT DARWIN_X86_64)
614      target_compile_features(${build_TARGET} PRIVATE cxx_std_17)
615  endif()
616
617  if(WINDOWS_MSVC_X86_64)
618    target_link_libraries(${build_TARGET} PRIVATE msvc-posix-compat)
619  endif()
620
621  android_clang_tidy(${build_TARGET})
622  android_target_dependency(${build_TARGET} all RUNTIME_OS_DEPENDENCIES)
623  android_target_properties(${build_TARGET} all "${RUNTIME_OS_PROPERTIES}")
624
625  if(ANDROID_CODE_COVERAGE)
626    # TODO Clean out existing .gcda files.
627  endif()
628
629  if(DEFINED build_INSTALL)
630    android_install_exe(${build_TARGET} ${build_INSTALL})
631  endif()
632endfunction()
633
634# Adds a protobuf library with the given name. It will export all the needed
635# headers, and libraries You can take a dependency on this by adding:
636# target_link_libraries(my_target ${name}) for your target. The generated
637# library will not use execeptions. Protobuf targets will be licensed under the
638# Apache-2.0 license.
639#
640# name: The name of the generated library. You can take a dependency on this
641# with setting target_linke_libraries(my_target ${name})
642#
643# protofiles: The set of protofiles to be included.
644function(android_add_protobuf name protofiles)
645  protobuf_generate_cpp(PROTO_SRCS PROTO_HDRS ${protofiles})
646  android_add_library(TARGET ${name} LICENSE Apache-2.0 SRC ${PROTO_SRCS}
647                                                            ${PROTO_HDRS})
648  target_link_libraries(${name} PUBLIC libprotobuf)
649  target_include_directories(${name} PUBLIC ${CMAKE_CURRENT_BINARY_DIR})
650  # Disable generation of information about every class with virtual functions
651  # for use by the C++ runtime type identification features (dynamic_cast and
652  # typeid). If you don't use those parts of the language, you can save some
653  # space by using this flag. Note that exception handling uses the same
654  # information, but it will generate it as needed. The  dynamic_cast operator
655  # can still be used for casts that do not require runtime type information,
656  # i.e. casts to void * or to unambiguous base classes.
657  target_compile_options(${name} PRIVATE -fno-rtti)
658  # This needs to be public, as we don't want the headers to start exposing
659  # exceptions.
660  target_compile_definitions(${name} PUBLIC -DGOOGLE_PROTOBUF_NO_RTTI)
661  android_clang_tidy(${name})
662endfunction()
663
664function(protobuf_generate_with_plugin)
665  include(CMakeParseArguments)
666
667  set(_options APPEND_PATH)
668  set(_singleargs LANGUAGE OUT_VAR EXPORT_MACRO PROTOC_OUT_DIR PLUGIN PLUGINOUT PROTOPATH HEADERFILEEXTENSION)
669  if(COMMAND target_sources)
670    list(APPEND _singleargs TARGET)
671  endif()
672  set(_multiargs PROTOS IMPORT_DIRS GENERATE_EXTENSIONS)
673
674  cmake_parse_arguments(protobuf_generate_with_plugin "${_options}" "${_singleargs}" "${_multiargs}" "${ARGN}")
675
676  if(NOT protobuf_generate_with_plugin_PROTOS AND NOT protobuf_generate_with_plugin_TARGET)
677    message(SEND_ERROR "Error: protobuf_generate_with_plugin called without any targets or source files")
678    return()
679  endif()
680
681  if(NOT protobuf_generate_with_plugin_OUT_VAR AND NOT protobuf_generate_with_plugin_TARGET)
682    message(SEND_ERROR "Error: protobuf_generate called without a target or output variable")
683    return()
684  endif()
685
686  if(NOT protobuf_generate_with_plugin_LANGUAGE)
687    set(protobuf_generate_with_plugin_LANGUAGE cpp)
688  endif()
689  string(TOLOWER ${protobuf_generate_with_plugin_LANGUAGE} protobuf_generate_with_plugin_LANGUAGE)
690
691  if(NOT protobuf_generate_with_plugin_PROTOC_OUT_DIR)
692    set(protobuf_generate_with_plugin_PROTOC_OUT_DIR ${CMAKE_CURRENT_BINARY_DIR})
693  endif()
694
695  if(protobuf_generate_with_plugin_EXPORT_MACRO AND protobuf_generate_with_plugin_LANGUAGE STREQUAL cpp)
696    set(_dll_export_decl "dllexport_decl=${protobuf_generate_with_plugin_EXPORT_MACRO}:")
697  endif()
698
699  if(NOT protobuf_generate_with_plugin_GENERATE_EXTENSIONS)
700    if(protobuf_generate_with_plugin_LANGUAGE STREQUAL cpp)
701        set(protobuf_generate_with_plugin_GENERATE_EXTENSIONS ${HEADERFILEEXTENSION} .pb.cc)
702    elseif(protobuf_generate_with_plugin_LANGUAGE STREQUAL python)
703      set(protobuf_generate_with_plugin_GENERATE_EXTENSIONS _pb2.py)
704    else()
705      message(SEND_ERROR "Error: protobuf_generatewith_plugin given unknown Language ${LANGUAGE}, please provide a value for GENERATE_EXTENSIONS")
706      return()
707    endif()
708  endif()
709
710  if(protobuf_generate_with_plugin_TARGET)
711    get_target_property(_source_list ${protobuf_generate_with_plugin_TARGET} SOURCES)
712    foreach(_file ${_source_list})
713      if(_file MATCHES "proto$")
714        list(APPEND protobuf_generate_with_plugin_PROTOS ${_file})
715      endif()
716    endforeach()
717  endif()
718
719  if(NOT protobuf_generate_with_plugin_PROTOS)
720    message(SEND_ERROR "Error: protobuf_generate_with_plugin could not find any .proto files")
721    return()
722  endif()
723
724  if(protobuf_generate_with_plugin_APPEND_PATH)
725    # Create an include path for each file specified
726    foreach(_file ${protobuf_generate_with_plugin_PROTOS})
727      get_filename_component(_abs_file ${_file} ABSOLUTE)
728      get_filename_component(_abs_path ${_abs_file} PATH)
729      list(FIND _protobuf_include_path ${_abs_path} _contains_already)
730      if(${_contains_already} EQUAL -1)
731          list(APPEND _protobuf_include_path -I ${_abs_path})
732      endif()
733    endforeach()
734  else()
735    set(_protobuf_include_path -I ${CMAKE_CURRENT_SOURCE_DIR})
736  endif()
737
738  foreach(DIR ${protobuf_generate_with_plugin_IMPORT_DIRS})
739    get_filename_component(ABS_PATH ${DIR} ABSOLUTE)
740    list(FIND _protobuf_include_path ${ABS_PATH} _contains_already)
741    if(${_contains_already} EQUAL -1)
742        list(APPEND _protobuf_include_path -I ${ABS_PATH})
743    endif()
744  endforeach()
745
746  separate_arguments(PROTOPATH)
747
748  set(_generated_srcs_all)
749  foreach(_proto ${protobuf_generate_with_plugin_PROTOS})
750    get_filename_component(_abs_file ${_proto} ABSOLUTE)
751    get_filename_component(_abs_dir ${_abs_file} DIRECTORY)
752    get_filename_component(_basename ${_proto} NAME_WE)
753    file(RELATIVE_PATH _rel_dir ${CMAKE_CURRENT_SOURCE_DIR} ${_abs_dir})
754
755    set(_generated_srcs)
756    foreach(_ext ${protobuf_generate_with_plugin_GENERATE_EXTENSIONS})
757      list(APPEND _generated_srcs "${protobuf_generate_with_plugin_PROTOC_OUT_DIR}/${_rel_dir}/${_basename}${_ext}")
758    endforeach()
759    list(APPEND _generated_srcs_all ${_generated_srcs})
760
761    add_custom_command(
762      OUTPUT ${_generated_srcs}
763      COMMAND  protobuf::protoc
764      ARGS --${protobuf_generate_with_plugin_LANGUAGE}_out ${_dll_export_decl}${protobuf_generate_with_plugin_PROTOC_OUT_DIR} ${_protobuf_include_path} ${PROTOPATH} ${_abs_file} --plugin=${PLUGIN} --plugin_out=${PLUGINOUT}
765      DEPENDS ${_abs_file} protobuf::protoc
766      COMMENT "Running ${protobuf_generate_with_plugin_LANGUAGE} protocol buffer compiler on ${_proto}"
767      VERBATIM )
768  endforeach()
769
770  set_source_files_properties(${_generated_srcs_all} PROPERTIES GENERATED TRUE)
771  if(protobuf_generate_with_plugin_OUT_VAR)
772    set(${protobuf_generate_with_plugin_OUT_VAR} ${_generated_srcs_all} PARENT_SCOPE)
773  endif()
774  if(protobuf_generate_with_plugin_TARGET)
775    target_sources(${protobuf_generate_with_plugin_TARGET} PRIVATE ${_generated_srcs_all})
776  endif()
777
778endfunction()
779
780function(PROTOBUF_GENERATE_CPP_WITH_PLUGIN HEADERFILEEXTENSION PLUGIN PLUGINOUT PROTOPATH SRCS HDRS)
781  cmake_parse_arguments(protobuf_generate_cpp_with_plugin "" "EXPORT_MACRO" "" ${ARGN})
782
783  set(_proto_files "${protobuf_generate_cpp_with_plugin_UNPARSED_ARGUMENTS}")
784  if(NOT _proto_files)
785      message(SEND_ERROR "Error: PROTOBUF_GENERATE_CPP_WITH_PLUGIN() called without any proto files")
786    return()
787  endif()
788
789  if(PROTOBUF_GENERATE_CPP_WITH_PLUGIN_APPEND_PATH)
790    set(_append_arg APPEND_PATH)
791  endif()
792
793  if(DEFINED Protobuf_IMPORT_DIRS)
794    set(_import_arg IMPORT_DIRS ${Protobuf_IMPORT_DIRS})
795  endif()
796
797  set(_outvar)
798  protobuf_generate_with_plugin(${_append_arg} LANGUAGE cpp EXPORT_MACRO ${protobuf_generate_cpp_with_plugin_EXPORT_MACRO} OUT_VAR _outvar ${_import_arg} PROTOS ${_proto_files} PLUGIN ${PLUGIN} PLUGINOUT ${PLUGINOUT} PROTOPATH ${PROTOPATH} HEADERFILEEXTENSION ${HEADERFILEEXTENSION})
799
800  set(${SRCS})
801  set(${HDRS})
802  foreach(_file ${_outvar})
803    if(_file MATCHES "cc$")
804      list(APPEND ${SRCS} ${_file})
805    else()
806      list(APPEND ${HDRS} ${_file})
807    endif()
808  endforeach()
809  set(${SRCS} ${${SRCS}} PARENT_SCOPE)
810  set(${HDRS} ${${HDRS}} PARENT_SCOPE)
811endfunction()
812
813# Adds a protozero library with the given plugin name.
814function(android_add_protobuf_with_plugin name headerfileextension plugin pluginout protolib PROTOPATH protofile genccpath)
815    message(
816      WARNING "protozero protofile: ${protofile}")
817  protobuf_generate_cpp_with_plugin(${headerfileextension} ${plugin} ${pluginout} ${PROTOPATH} PROTO_SRCS PROTO_HDRS ${protofile})
818  get_filename_component(PROTO_SRCS_ABS ${PROTO_SRCS} ABSOLUTE)
819  set(genccpath2 ${CMAKE_CURRENT_BINARY_DIR}/${genccpath})
820  set_source_files_properties(${genccpath2} PROPERTIES GENERATED TRUE)
821  android_add_library(TARGET ${name} LICENSE Apache-2.0 SRC ${genccpath2}
822                                                            ${PROTO_HDRS})
823  target_link_libraries(${name} PUBLIC ${protolib})
824  target_include_directories(${name} PUBLIC ${CMAKE_CURRENT_BINARY_DIR})
825  # Disable generation of information about every class with virtual functions
826  # for use by the C++ runtime type identification features (dynamic_cast and
827  # typeid). If you don't use those parts of the language, you can save some
828  # space by using this flag. Note that exception handling uses the same
829  # information, but it will generate it as needed. The  dynamic_cast operator
830  # can still be used for casts that do not require runtime type information,
831  # i.e. casts to void * or to unambiguous base classes.
832  target_compile_options(${name} PRIVATE -fno-rtti)
833  # This needs to be public, as we don't want the headers to start exposing
834  # exceptions.
835  target_compile_definitions(${name} PUBLIC -DGOOGLE_PROTOBUF_NO_RTTI)
836  android_clang_tidy(${name})
837endfunction()
838
839# For adding big proto files that mingw can't handle.
840function(android_add_big_protobuf name protofiles)
841  android_add_protobuf(name protofiles)
842endfunction()
843
844# This function generates the hw config file. It translates android-
845# emu/androd/avd/hardware-properties.ini -> android/avd/hw-config-defs.h
846#
847# This file will be placed on the current binary dir, so it can be included if
848# this directory is on the include path.
849function(android_generate_hw_config)
850  set(ANDROID_HW_CONFIG_H
851      ${CMAKE_CURRENT_BINARY_DIR}/avd_config/android/avd/hw-config-defs.h)
852  add_custom_command(
853    OUTPUT ${ANDROID_HW_CONFIG_H}
854    COMMAND
855      python ${ANDROID_QEMU2_TOP_DIR}/android/scripts/gen-hw-config.py
856      ${ANDROID_QEMU2_TOP_DIR}/android/android-emu/android/avd/hardware-properties.ini
857      ${ANDROID_HW_CONFIG_H}
858    DEPENDS
859      ${ANDROID_QEMU2_TOP_DIR}/android/android-emu/android/avd/hardware-properties.ini
860    VERBATIM)
861  android_add_library(TARGET android-hw-config LICENSE Apache-2.0
862                      SRC ${ANDROID_HW_CONFIG_H} dummy.c)
863  set_source_files_properties(
864    ${ANDROID_HW_CONFIG_H}
865    PROPERTIES GENERATED TRUE SKIP_AUTOGEN ON HEADER_FILE_ONLY TRUE)
866  target_include_directories(android-hw-config
867                             PUBLIC ${CMAKE_CURRENT_BINARY_DIR}/avd_config)
868endfunction()
869
870# Copies the list of test data files to the given destination The test data
871# resides in the prebuilts/android-emulator- build/common/testdata folder.
872#
873# TGT The target as part of which the test files should be copied. SOURCE_LIST
874# The list of files that need to be copied DEST The subdirectory under TGT where
875# the files should be copied to.
876function(android_copy_test_files TGT SOURCE_LIST DEST)
877  get_filename_component(
878    TESTDATA_ROOT
879    "${ANDROID_QEMU2_TOP_DIR}/../../prebuilts/android-emulator-build/common/"
880    ABSOLUTE)
881
882  foreach(SRC_FILE ${SOURCE_LIST})
883    get_filename_component(DEST_FILE ${SRC_FILE} NAME)
884    add_custom_command(
885      TARGET ${TGT}
886      PRE_BUILD
887      COMMAND
888        ${CMAKE_COMMAND} -E copy_if_different ${TESTDATA_ROOT}/${SRC_FILE}
889        $<TARGET_FILE_DIR:${TGT}>/${DEST}/${DEST_FILE})
890  endforeach()
891endfunction()
892
893# Copies the given file from ${SRC} -> ${DST} if needed.
894function(android_copy_file TGT SRC DST)
895  add_custom_command(
896    TARGET ${TGT} PRE_BUILD COMMAND ${CMAKE_COMMAND} -E copy_if_different
897                                    ${SRC} ${DST} MAIN_DEPENDENCY ${SRC})
898endfunction()
899
900# Copies the given test directory to the given destination. The test data
901# resides in the prebuilts/android-emulator- build/common/testdata folder.
902#
903# TGT The target as part of which the test files should be copied. SRC_DIR The
904# source directories to copy., DST_DIR The subdirectory under TGT where the
905# files should be copied to.
906function(android_copy_test_dir TGT SRC_DIR DST_DIR)
907  get_filename_component(
908    TESTDATA_ROOT
909    "${ANDROID_QEMU2_TOP_DIR}/../../prebuilts/android-emulator-build/common/testdata"
910    ABSOLUTE)
911
912  add_custom_command(
913    TARGET ${TGT} POST_BUILD
914    COMMAND ${CMAKE_COMMAND} -E copy_directory ${TESTDATA_ROOT}/${SRC_DIR}
915            $<TARGET_FILE_DIR:${TGT}>/${DST_DIR})
916endfunction()
917
918# Append the given flags to the existing CMAKE_C_FLAGS. Be careful as these
919# flags are global and used for every target! Note this will not do anything
920# under vs for now
921function(add_c_flag FLGS)
922  foreach(FLAG ${FLGS})
923    set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${FLAG}" PARENT_SCOPE)
924    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${FLAG}" PARENT_SCOPE)
925  endforeach()
926endfunction()
927
928function(add_cxx_flag FLGS)
929  foreach(FLAG ${FLGS})
930    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${FLAG}" PARENT_SCOPE)
931  endforeach()
932endfunction()
933
934# This function retrieves th git_version, or reverting to the date if we cannot
935# fetch it.
936#
937# VER The variable to set the version in Sets ${VER} The version as reported by
938# git, or the date
939function(get_git_version VER)
940  execute_process(
941    COMMAND "git" "describe" WORKING_DIRECTORY ${ANDROID_QEMU2_TOP_DIR}
942    RESULT_VARIABLE GIT_RES OUTPUT_VARIABLE STD_OUT ERROR_VARIABLE STD_ERR)
943  if(NOT "${GIT_RES}" STREQUAL "0")
944    message(
945      WARNING
946        "Unable to retrieve git version from ${ANDROID_QEMU2_TOP_DIR}, out: ${STD_OUT}, err: ${STD_ERR}"
947    )
948    if(NOT MSVC)
949      execute_process(
950        COMMAND "date" "+%Y-%m-%d" WORKING_DIRECTORY ${ANDROID_QEMU2_TOP_DIR}
951        RESULT_VARIABLE DATE_RES OUTPUT_VARIABLE STD_OUT ERROR_VARIABLE STD_ERR)
952      if(NOT "${DATE_RES}" STREQUAL "0")
953        message(FATAL_ERROR "Unable to retrieve date!")
954      endif()
955    else()
956      execute_process(
957        COMMAND "date" "/T" WORKING_DIRECTORY ${ANDROID_QEMU2_TOP_DIR}
958        RESULT_VARIABLE DATE_RES OUTPUT_VARIABLE STD_OUT ERROR_VARIABLE STD_ERR)
959    endif()
960  endif()
961
962  # Clean up and make visibile
963  string(REPLACE "\n" "" STD_OUT "${STD_OUT}")
964  set(${VER} ${STD_OUT} PARENT_SCOPE)
965endfunction()
966
967# VER The variable to set the sha in Sets ${VER} The latest sha as reported by
968# git
969function(get_git_sha VER)
970  execute_process(
971    COMMAND "git" "log" "-n" "1" "--pretty=format:'%H'"
972    WORKING_DIRECTORY ${ANDROID_QEMU2_TOP_DIR} RESULT_VARIABLE GIT_RES
973    OUTPUT_VARIABLE STD_OUT ERROR_VARIABLE STD_ERR)
974  if(NOT "${GIT_RES}" STREQUAL "0")
975    message(
976      FATAL_ERROR
977        "Unable to retrieve git version from ${ANDROID_QEMU2_TOP_DIR} : out: ${STD_OUT}, err: ${STD_ERR}"
978    )
979  endif()
980
981  # Clean up and make visibile
982  string(REPLACE "\n" "" STD_OUT "${STD_OUT}")
983  set(${VER} ${STD_OUT} PARENT_SCOPE)
984endfunction()
985
986# Constructs a linker command that will make sure the whole archive is included,
987# not just the ones referenced.
988#
989# . LIBCMD The variable which will contain the complete linker command . LIBNAME
990# The archive that needs to be included completely
991function(android_complete_archive LIBCMD LIBNAME)
992  if(DARWIN_X86_64)
993    set(${LIBCMD} "-Wl,-force_load,$<TARGET_FILE:${LIBNAME}>" PARENT_SCOPE)
994  elseif(WINDOWS_MSVC_X86_64)
995    if(MSVC)
996      # The native build calls the linker directly
997      set(${LIBCMD} "-wholearchive:$<TARGET_FILE:${LIBNAME}>" PARENT_SCOPE)
998    else()
999      # The cross compiler calls the linker through clang.
1000      set(${LIBCMD} "-Wl,-wholearchive:$<TARGET_FILE:${LIBNAME}>" PARENT_SCOPE)
1001    endif()
1002  else()
1003    set(${LIBCMD} "-Wl,-whole-archive" ${LIBNAME} "-Wl,-no-whole-archive"
1004        PARENT_SCOPE)
1005  endif()
1006endfunction()
1007
1008# Constructs the upstream qemu executable.
1009#
1010# ANDROID_AARCH The android architecture name QEMU_AARCH The qemu architecture
1011# name. CONFIG_AARCH The configuration architecture used. STUBS The set of stub
1012# sources to use. CPU The target cpu architecture used by qemu
1013#
1014# (Maybe on one day we will standardize all the naming, between qemu and configs
1015# and cpus..)
1016function(android_build_qemu_variant)
1017  # Parse arguments
1018  set(options INSTALL)
1019  set(oneValueArgs CPU EXE)
1020  set(multiValueArgs SOURCES DEFINITIONS LIBRARIES)
1021  cmake_parse_arguments(qemu_build "${options}" "${oneValueArgs}"
1022                        "${multiValueArgs}" ${ARGN})
1023
1024  # translate various names.. because of inconsistent naming in the code base..
1025  if(qemu_build_CPU STREQUAL "x86_64")
1026    set(CPU "i386")
1027    set(QEMU_AARCH "x86_64")
1028    set(CONFIG_AARCH "x86_64")
1029  elseif(qemu_build_CPU STREQUAL "i386")
1030    set(CPU "i386")
1031    set(QEMU_AARCH "i386")
1032    set(CONFIG_AARCH "x86")
1033  elseif(qemu_build_CPU STREQUAL "aarch64")
1034    set(CPU "arm")
1035    set(QEMU_AARCH "aarch64")
1036    set(CONFIG_AARCH "arm64")
1037  elseif(qemu_build_CPU STREQUAL "armel")
1038    set(CPU "arm")
1039    set(QEMU_AARCH "arm")
1040    set(CONFIG_AARCH "arm")
1041  else()
1042    message(FATAL_ERROR "Unknown cpu type.")
1043  endif()
1044
1045  # Workaround b/121393952, older cmake does not have proper object archives
1046  android_complete_archive(QEMU_COMPLETE_LIB "qemu2-common")
1047  android_add_executable(
1048    TARGET ${qemu_build_EXE}
1049    LICENSE Apache-2.0
1050    LIBNAME
1051      qemu-system
1052      URL
1053      "https://android.googlesource.com/platform/external/qemu/+/refs/heads/emu-master-dev"
1054    REPO "${ANDROID_QEMU2_TOP_DIR}"
1055    NOTICE "REPO/LICENSES/LICENSE.APACHE2"
1056    SRC ${qemu_build_SOURCES} ${qemu-system-${QEMU_AARCH}_sources}
1057        ${qemu-system-${QEMU_AARCH}_generated_sources})
1058  target_include_directories(
1059    ${qemu_build_EXE} PRIVATE android-qemu2-glue/config/target-${CONFIG_AARCH}
1060                              target/${CPU})
1061  target_compile_definitions(${qemu_build_EXE}
1062                             PRIVATE ${qemu_build_DEFINITIONS})
1063  target_link_libraries(${qemu_build_EXE} PRIVATE ${QEMU_COMPLETE_LIB}
1064                                                  ${qemu_build_LIBRARIES})
1065
1066  # Make the common dependency explicit, as some generators might not detect it
1067  # properly (Xcode/MSVC native)
1068  add_dependencies(${qemu_build_EXE} qemu2-common)
1069  # XCode bin places this not where we want this...
1070  if(qemu_build_INSTALL)
1071    set_target_properties(
1072      ${qemu_build_EXE}
1073      PROPERTIES
1074        RUNTIME_OUTPUT_DIRECTORY
1075        "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/qemu/${ANDROID_TARGET_OS_FLAVOR}-${ANDROID_TARGET_ARCH}"
1076    )
1077    android_install_exe(${qemu_build_EXE}
1078                        "./qemu/${ANDROID_TARGET_OS_FLAVOR}-${ANDROID_TARGET_ARCH}")
1079  endif()
1080endfunction()
1081
1082# Constructs the qemu executable.
1083#
1084# ANDROID_AARCH The android architecture name STUBS The set of stub sources to
1085# use.
1086function(android_add_qemu_executable ANDROID_AARCH STUBS)
1087  if (WINDOWS_MSVC_X86_64)
1088    set(WINDOWS_LAUNCHER emulator-winqt-launcher)
1089  endif()
1090  android_build_qemu_variant(
1091    INSTALL
1092    EXE qemu-system-${ANDROID_AARCH}
1093    CPU ${ANDROID_AARCH}
1094    SOURCES android-qemu2-glue/main.cpp vl.c ${STUBS}
1095    DEFINITIONS
1096      -DNEED_CPU_H -DCONFIG_ANDROID
1097      -DANDROID_SDK_TOOLS_REVISION=${OPTION_SDK_TOOLS_REVISION}
1098      -DANDROID_SDK_TOOLS_BUILD_NUMBER=${OPTION_SDK_TOOLS_BUILD_NUMBER}
1099    LIBRARIES libqemu2-glue
1100              libqemu2-glue-vm-operations
1101              libqemu2-util
1102              emulator-libui
1103              android-emu
1104              android-qemu-deps
1105              android-qemu-deps-headful
1106              emulator-libusb
1107              ${WINDOWS_LAUNCHER})
1108endfunction()
1109
1110# Constructs the qemu headless executable.
1111#
1112# ANDROID_AARCH The android architecture name STUBS The set of stub sources to
1113# use.
1114function(android_add_qemu_headless_executable ANDROID_AARCH STUBS)
1115  android_build_qemu_variant(
1116    INSTALL
1117    EXE qemu-system-${ANDROID_AARCH}-headless
1118    CPU ${ANDROID_AARCH}
1119    SOURCES android-qemu2-glue/main.cpp vl.c ${STUBS}
1120    DEFINITIONS
1121      -DNEED_CPU_H -DCONFIG_ANDROID -DCONFIG_HEADLESS
1122      -DANDROID_SDK_TOOLS_REVISION=${OPTION_SDK_TOOLS_REVISION}
1123      -DANDROID_SDK_TOOLS_BUILD_NUMBER=${OPTION_SDK_TOOLS_BUILD_NUMBER}
1124    LIBRARIES libqemu2-glue
1125              libqemu2-glue-vm-operations
1126              libqemu2-util
1127              android-emu
1128              emulator-libui-headless
1129              android-qemu-deps
1130              android-qemu-deps-headless
1131              emulator-libusb)
1132endfunction()
1133
1134# Constructs the qemu upstream executable.
1135#
1136# ANDROID_AARCH The android architecture name STUBS The set of stub sources to
1137# use.
1138function(android_add_qemu_upstream_executable ANDROID_AARCH STUBS)
1139  android_build_qemu_variant(
1140    # INSTALL We do not install this target.
1141    EXE qemu-upstream-${ANDROID_AARCH}
1142    CPU ${ANDROID_AARCH}
1143    SOURCES vl.c ${STUBS}
1144    DEFINITIONS -DNEED_CPU_H
1145    LIBRARIES android-emu
1146              libqemu2-glue
1147              libqemu2-glue-vm-operations
1148              libqemu2-util
1149              SDL2::SDL2
1150              android-qemu-deps
1151              android-qemu-deps-headful
1152              emulator-libusb)
1153endfunction()
1154
1155# Copies a shared library
1156function(android_copy_shared_lib TGT SHARED_LIB NAME)
1157  android_copy_file(
1158    ${TGT} $<TARGET_FILE:${SHARED_LIB}>
1159    $<TARGET_FILE_DIR:${TGT}>/lib64/${NAME}${CMAKE_SHARED_LIBRARY_SUFFIX})
1160endfunction()
1161
1162function(android_log MSG)
1163  if(ANDROID_LOG)
1164    message(STATUS ${MSG})
1165  endif()
1166endfunction()
1167
1168function(android_validate_sha256 FILE EXPECTED)
1169  file(SHA256 ${FILE} CHECKSUM)
1170  if(NOT CHECKSUM STREQUAL "${EXPECTED}")
1171    get_filename_component(
1172      DEST "${ANDROID_QEMU2_TOP_DIR}/../../device/generic/goldfish-opengl"
1173      ABSOLUTE)
1174    message(
1175      FATAL_ERROR
1176        "Checksum mismatch for ${FILE} = ${CHECKSUM}, expecting ${EXPECTED}, you need to regenerate the cmake files by executing 'make' in ${DEST}"
1177    )
1178  endif()
1179endfunction()
1180
1181# Uploads the symbols to the breakpad crash server
1182function(android_upload_symbols TGT)
1183  find_package(PythonInterp)
1184  if(NOT ANDROID_EXTRACT_SYMBOLS)
1185    return()
1186  endif()
1187  set(DEST "${ANDROID_SYMBOL_DIR}/${TGT}.sym")
1188  set(LOG "${ANDROID_SYMBOL_DIR}/${TGT}.log")
1189  install(
1190    CODE # Upload the symbols, with warnings/error logging only.
1191         "execute_process(COMMAND \"${PYTHON_EXECUTABLE}\"
1192                             \"${ANDROID_QEMU2_TOP_DIR}/android/build/python/aemu/upload_symbols.py\"
1193                             \"--symbol_file\" \"${DEST}\"
1194                             \"--environment\" \"${OPTION_CRASHUPLOAD}\"
1195                             OUTPUT_FILE ${LOG}
1196                             ERROR_FILE ${LOG})\n
1197    if (EXISTS ${LOG})
1198      FILE(READ ${LOG} contents)
1199      STRING(STRIP \"\$\{contents\}\" contents)
1200    else()
1201        SET(contents \"No logfile in ${LOG} for ${DEST} was created\")
1202    endif()
1203    MESSAGE(STATUS \$\{contents\})")
1204endfunction()
1205
1206# Installs the given target executable into the given destinations. Symbols will
1207# be extracted during build, and uploaded during install.
1208function(android_install_exe TGT)
1209    install(TARGETS ${TGT} RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX})
1210
1211  # Make it available on the build server
1212  # android_extract_symbols(${TGT})
1213  # android_upload_symbols(${TGT})
1214  # android_install_license(${TGT} ${DST}/${TGT}${CMAKE_EXECUTABLE_SUFFIX})
1215endfunction()
1216
1217# Installs the given shared library. The shared library will end up in ../lib64
1218# Symbols will be extracted during build, and uploaded during install.
1219function(android_install_shared TGT)
1220  install(
1221      TARGETS ${TGT} RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX} LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX})
1222  # android_extract_symbols(${TGT})
1223  # android_upload_symbols(${TGT})
1224  # android_install_license(${TGT} ${TGT}${CMAKE_SHARED_LIBRARY_SUFFIX})
1225endfunction()
1226
1227# Strips the given prebuilt executable during install..
1228function(android_strip_prebuilt FNAME)
1229  # MSVC stores debug info in seperate file, so no need to strip
1230  if(NOT WINDOWS_MSVC_X86_64)
1231    install(
1232      CODE "if(CMAKE_INSTALL_DO_STRIP) \n
1233                        execute_process(COMMAND ${CMAKE_STRIP} \"$ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}/${FNAME}\")\n
1234                      endif()\n
1235                     ")
1236  endif()
1237endfunction()
1238
1239# Extracts symbols from a file that is not built. This is mainly here if we wish
1240# to extract symbols for a prebuilt file.
1241function(android_extract_symbols_file FNAME)
1242  get_filename_component(BASENAME ${FNAME} NAME)
1243  set(DEST "${ANDROID_SYMBOL_DIR}/${BASENAME}.sym")
1244
1245  if(WINDOWS_MSVC_X86_64)
1246    # In msvc we need the pdb to generate the symbols, pdbs are not yet
1247    # available for The prebuilts. b/122728651
1248    message(
1249      WARNING
1250        "Extracting symbols requires access to the pdb for ${FNAME}, ignoring for now."
1251    )
1252    return()
1253  endif()
1254  install(
1255    CODE "execute_process(COMMAND ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/dump_syms -g ${FNAME} OUTPUT_FILE ${DEST} RESULT_VARIABLE RES ERROR_QUIET) \n
1256                 message(STATUS \"Extracted symbols for ${FNAME} ${RES}\")")
1257  install(
1258    CODE "execute_process(COMMAND ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/sym_upload ${DEST} ${ANDROID_SYMBOL_URL}  OUTPUT_VARIABLE RES ERROR_QUIET) \n
1259                 message(STATUS \"Uploaded symbols for ${FNAME} --> ${ANDROID_SYMBOL_URL} ${RES}\")"
1260  )
1261endfunction()
1262
1263# Extracts the symbols from the given target if extraction is requested. TODO:
1264# We need generator expressions to move this to the install phase. Which are
1265# available in cmake 3.13
1266function(android_extract_symbols TGT)
1267  if(NOT ANDROID_EXTRACT_SYMBOLS)
1268    # Note: we do not need to extract symbols on windows for uploading.
1269    return()
1270  endif()
1271  set(DEST "${ANDROID_SYMBOL_DIR}/${TGT}.sym")
1272  add_custom_command(
1273    TARGET ${TGT} POST_BUILD COMMAND dump_syms "$<TARGET_FILE:${TGT}>" > ${DEST}
1274    DEPENDS dump_syms
1275    COMMENT "Extracting symbols for ${TGT}" VERBATIM)
1276endfunction()
1277
1278# Make the compatibility layer available for every target
1279if(WINDOWS_MSVC_X86_64 AND NOT INCLUDE_MSVC_POSIX)
1280  set(INCLUDE_MSVC_POSIX 1)
1281  add_subdirectory(${ANDROID_QEMU2_TOP_DIR}/android/msvc-posix-compat/
1282                   msvc-posix-compat)
1283endif()
1284
1285# Rule to build cf crosvm based on a combination of dependencies
1286# built locally / prebuilt
1287function(android_crosvm_build DEP)
1288    message(STATUS "building crosvm with dependency ${DEP}")
1289    set(CMAKE_CROSVM_HOST_PACKAGE_TOOLS_PATH
1290        "${ANDROID_QEMU2_TOP_DIR}/../../prebuilts/android-emulator-build/common/cf-host-package")
1291    set(CMAKE_CROSVM_BUILD_SCRIPT_PATH
1292        "${CMAKE_CROSVM_HOST_PACKAGE_TOOLS_PATH}/crosvm-build.sh")
1293
1294    set(CMAKE_CROSVM_REPO_TOP_LEVEL_PATH
1295        "${ANDROID_QEMU2_TOP_DIR}/../..")
1296    set(CMAKE_CROSVM_BUILD_ENV_DIR
1297        "${CMAKE_BINARY_DIR}/crosvm-build-env")
1298    set(CMAKE_CROSVM_GFXSTREAM_BUILD_DIR
1299        "${CMAKE_BINARY_DIR}")
1300    set(CMAKE_CROSVM_DIST_DIR
1301        "${CMAKE_INSTALL_PREFIX}")
1302    add_custom_command(
1303        OUTPUT "${CMAKE_CROSVM_BUILD_ENV_DIR}/release/crosvm"
1304        COMMAND
1305            "${CMAKE_CROSVM_BUILD_SCRIPT_PATH}"
1306            "${CMAKE_CROSVM_REPO_TOP_LEVEL_PATH}"
1307            "${CMAKE_CROSVM_HOST_PACKAGE_TOOLS_PATH}"
1308            "${CMAKE_CROSVM_BUILD_ENV_DIR}"
1309            "${CMAKE_CROSVM_GFXSTREAM_BUILD_DIR}"
1310            "${CMAKE_CROSVM_DIST_DIR}"
1311        DEPENDS ${DEP})
1312endfunction()
1313