| # Copyright 2018 The Android Open Source Project |
| # |
| # Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with |
| # the License. You may obtain a copy of the License at |
| # |
| # http://www.apache.org/licenses/LICENSE-2.0 |
| # |
| # Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an |
| # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the |
| # specific language governing permissions and limitations under the License. |
| |
| # This contains a set of definitions to make working with prebuilts easier and manageable. |
| |
| set(PREBUILT_COMMON "BLUEZ;LZ4") |
| if(NOT ANDROID_TARGET_TAG MATCHES "windows_msvc.*") |
| list(APPEND PREBUILT_COMMON "X264") |
| endif() |
| |
| function(android_add_prebuilt_library PKG MODULE LOCATION INCLUDES DEFINTIONS) |
| if(NOT TARGET ${PKG}::${MODULE}) |
| add_library(${PKG}::${MODULE} STATIC IMPORTED GLOBAL) |
| set_target_properties(${PKG}::${MODULE} |
| PROPERTIES IMPORTED_LOCATION |
| "${LOCATION}${CMAKE_STATIC_LIBRARY_SUFFIX}" |
| INTERFACE_INCLUDE_DIRECTORIES |
| "${INCLUDES}" |
| INTERFACE_COMPILE_DEFINITIONS |
| "${DEFINTIONS}") |
| |
| android_log("set_target_properties(${PKG}::${MODULE} PROPERTIES |
| IMPORTED_LOCATION '${LOCATION}${CMAKE_STATIC_LIBRARY_SUFFIX}' |
| INTERFACE_INCLUDE_DIRECTORIES '${INCLUDES}' |
| INTERFACE_COMPILE_DEFINITIONS '${DEFINTIONS}' |
| )") |
| endif() |
| endfunction() |
| |
| # Internal function for simple packages. |
| function(simple_prebuilt Package) |
| # A simple common package.. |
| string(TOLOWER ${Package} pkg) |
| string(TOUPPER ${Package} PKG) |
| get_filename_component( |
| PREBUILT_ROOT "${ANDROID_QEMU2_TOP_DIR}/../../prebuilts/android-emulator-build/common/${pkg}/${ANDROID_TARGET_TAG}" |
| ABSOLUTE) |
| |
| android_add_prebuilt_library("${PKG}" "${PKG}" "${PREBUILT_ROOT}/lib/lib${pkg}" "${PREBUILT_ROOT}/include" "" "") |
| set(${PKG}_INCLUDE_DIRS "${PREBUILT_ROOT}/include" PARENT_SCOPE) |
| set(${PKG}_INCLUDE_DIR "${PREBUILT_ROOT}/include" PARENT_SCOPE) |
| set(${PKG}_LIBRARIES "${PREBUILT_ROOT}/lib/lib${pkg}${CMAKE_STATIC_LIBRARY_SUFFIX}" PARENT_SCOPE) |
| set(${PKG}_FOUND TRUE PARENT_SCOPE) |
| set(PACKAGE_EXPORT "${PKG}_INCLUDE_DIR;${PKG}_INCLUDE_DIRS;${PKG}_LIBRARIES;${PKG}_FOUND" PARENT_SCOPE) |
| endfunction() |
| |
| # This function is to be used as a replacement for find_package it will discover the internal prebuilts needed to |
| # compile the emulator |
| |
| # It will revert to standard find_package if the TARGET_TAG and QEMU2_TOP_DIR properties are not defined. |
| # |
| # If they are defined the emu-{Package}-config.cmake will be executed. This script should mimic FindPackage for the |
| # specific Package, it should set all variables of relevance and declare these in PACKAG_EXPORT so they can be made |
| # visible. |
| # |
| # See: emu-curl-config.cmake for a simple example. See: emu-protobuf-config.cmake for a more complicated example. |
| # |
| # Package The package which we wish to resolve |
| function(prebuilt Package) |
| string(TOLOWER ${Package} pkg) |
| string(TOUPPER ${Package} PKG) |
| if(${PKG}_FOUND) |
| android_log("${Package} has already been found") |
| return() |
| endif() |
| if(DEFINED ANDROID_QEMU2_TOP_DIR AND DEFINED ANDROID_TARGET_TAG) |
| if(${PKG} IN_LIST PREBUILT_COMMON) |
| simple_prebuilt(${Package}) |
| else() |
| get_filename_component(PREBUILT_ROOT "${ANDROID_QEMU2_TOP_DIR}/../.." ABSOLUTE) |
| |
| # We make sure we use our internal cmake directory to resolve packages |
| get_filename_component(ANDROID_TOOLS_DIRECTORY "${ANDROID_QEMU2_TOP_DIR}/android/build/cmake/config" ABSOLUTE) |
| set(${Package}_DIR "${ANDROID_TOOLS_DIRECTORY}") |
| |
| # This will cause cmake to look for emu-${pkg}-config.cmake in the directory above. |
| find_package(${Package} REQUIRED NAMES "emu-${pkg}") |
| |
| # Oh oh, this could be bad.. (But usually isn't) |
| foreach(LIB ${${PKG}_LIBRARIES}) |
| if(NOT ${LIB} MATCHES "-l.*|-L.*|${PREBUILT_ROOT}.*") |
| android_log("Discovered ${Package} lib ${LIB} which is outside of tree ${PREBUILT_ROOT}!") |
| endif() |
| endforeach() |
| endif() |
| foreach(INC ${${PKG}_INCLUDE_DIRS}) |
| if(NOT EXISTS ${INC}) |
| message(FATAL_ERROR "The include directory ${INC} of ${Package} does not exist..") |
| endif() |
| endforeach() |
| android_log("Found ${Package}: ${${PKG}_LIBRARIES} (Prebuilt version)") |
| |
| # Export the variables to parent |
| foreach(TO_EXP ${PACKAGE_EXPORT}) |
| set(${TO_EXP} "${${TO_EXP}}" PARENT_SCOPE) |
| endforeach() |
| else() |
| |
| # You are not using our make system! |
| android_log("${Package} is outside of emulator build!") |
| find_package(${PKG} REQUIRED) |
| endif() |
| endfunction(prebuilt pkg) |
| |
| # Installs the given src file into the given destination |
| function(internal_android_install_file SRC DST_DIR) |
| # src could be a symlink, so let's resolve it. |
| get_filename_component(REAL_SRC "${SRC}" REALPATH) |
| |
| # The names without directories of the src and resolved src. |
| get_filename_component(FNAME "${SRC}" NAME) |
| get_filename_component(FNAME_REAL "${REAL_SRC}" NAME) |
| |
| # Okay, we now need to determine if REAL_SRC is an executable, or file |
| set(PYTHON_SCRIPT "import os; print os.path.isfile('${REAL_SRC}') and os.access('${REAL_SRC}', os.X_OK)") |
| execute_process(COMMAND python -c "${PYTHON_SCRIPT}" |
| WORKING_DIRECTORY ${ANDROID_QEMU2_TOP_DIR} |
| RESULT_VARIABLE SUCCESS |
| OUTPUT_VARIABLE STD_OUT |
| ERROR_VARIABLE STD_ERR) |
| string(REPLACE "\n" "" STD_OUT "${STD_OUT}") |
| if(STD_OUT) |
| android_log(STATUS "install(PROGRAMS ${SRC} ${REAL_SRC} DESTINATION ${DST_DIR})") |
| install(PROGRAMS ${SRC} DESTINATION ${DST_DIR}) |
| android_strip_prebuilt("${DST_DIR}/${FNAME}") |
| # Check if we have a symlink, gradle doesn't support symlinks, so we are |
| # copying it 2x |
| if(NOT ${SRC} STREQUAL ${REAL_SRC}) |
| android_log("${SRC} ==> ${REAL_SRC}") |
| install(PROGRAMS ${REAL_SRC} DESTINATION ${DST_DIR}) |
| android_strip_prebuilt("${DST_DIR}/${FNAME_REAL}") |
| endif() |
| else() |
| install(FILES ${SRC} DESTINATION ${DST_DIR}) |
| # Let's see if it is a shared library |
| if (${SRC} MATCHES ".+${CMAKE_SHARED_LIBRARY_SUFFIX}(\\.[0-9]+)$") |
| # Note we should eventually remove this: b/1381606 |
| android_strip_prebuilt("${DST_DIR}/${FNAME}") |
| endif() |
| if(NOT ${SRC} STREQUAL ${REAL_SRC}) |
| android_log("${SRC} ==> ${REAL_SRC}") |
| install(FILES ${REAL_SRC} DESTINATION ${DST_DIR}) |
| # Check if we have a symlink, gradle doesn't support symlinks, so we are |
| # copying it 2x |
| if (${REAL_SRC} MATCHES ".+${CMAKE_SHARED_LIBRARY_SUFFIX}(\\.[0-9]+)$") |
| android_strip_prebuilt("${DST_DIR}/${FNAME_REAL}") |
| endif() |
| endif() |
| endif() |
| endfunction() |
| |
| # Installs the given dependency, this will make it part of the final release. |
| function(android_install_dependency TARGET_TAG INSTALL_DEPENDENCIES) |
| if(TARGET_TAG STREQUAL "${ANDROID_TARGET_TAG}" OR TARGET_TAG STREQUAL "all") |
| # Link to existing target if there. |
| if(NOT TARGET ${INSTALL_DEPENDENCIES}) |
| message(FATAL_ERROR "Dependencies ${INSTALL_DEPENDENCIES} has not been declared (yet?)") |
| endif() |
| get_target_property(FILE_LIST ${INSTALL_DEPENDENCIES} SOURCES) |
| foreach(FNAME ${FILE_LIST}) |
| if(NOT FNAME MATCHES ".*dummy.c") |
| string(REPLACE "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/" "" DST_FILE ${FNAME}) |
| get_filename_component(DST_DIR "${DST_FILE}" DIRECTORY) |
| internal_android_install_file(${FNAME} ${DST_DIR}) |
| endif() |
| endforeach() |
| endif() |
| endfunction() |
| |
| # Binplaces the given source file to the given destination as part of the target |
| # |
| # It will be registered as a generated source. |
| function(android_binplace TARGET SRC_FILE DEST_FILE) |
| if(NOT EXISTS ${SRC_FILE}) |
| message(FATAL_ERROR "The target ${TARGET} depends on a dependency: ${SRC_FILE} that does not exist!") |
| endif() |
| |
| if(DEST_FILE MATCHES ".*\\.[O|o][B|b][J|j]" AND MSVC) |
| # We don't want to expose .OBJ files to the MSVC linker, so we will post copy those. |
| message(STATUS "Marking ${DEST_FILE} as post copy for windows. Modifications to this file will not be detected.") |
| add_custom_command(TARGET ${TARGET} POST_BUILD |
| COMMAND ${CMAKE_COMMAND} -E copy_if_different "${SRC_FILE}" "${DEST_FILE}") |
| else() |
| target_sources(${TARGET} PRIVATE ${DEST_FILE}) |
| add_custom_command(OUTPUT "${DEST_FILE}" COMMAND ${CMAKE_COMMAND} -E copy_if_different "${SRC_FILE}" "${DEST_FILE}") |
| endif() |
| endfunction() |
| |
| # Add the runtime dependencies, i.e. the set of libs that need to be copied over to the proper location in order to run |
| # the executable. |
| # |
| # RUN_TARGET The executable that needs these run time dependencies |
| # |
| # TARGET_TAG The android target tag for which these are applicable, or all for all targets. |
| # |
| # RUN_TARGET_DEPENDENCIES: . List of SRC>DST pairs that contains individual file dependencies. . List of |
| # SRC_DIR>>DST pairs that contains directorie depedencies. |
| # |
| # For example: set(MY_FOO_DEPENDENCIES # copy from /tmp/a/b.txt to lib/some/dir/c.txt "/tmp/a/b.txt>lib/some/dir/c.txt;" |
| # # recursively copy /tmp/dirs to lib/x lib/some/dir/c.txt "/tmp/dirs/*>>lib/x") |
| # |
| # Note that this relies on every binary being binplaced in the root, which implies that this will not work with every |
| # generator. |
| # |
| # This works by creating an empty dummy target that relies on a set of sources that are the files we want to copy over. |
| # We construct the list of files we want to copy over and create a custom command that does the copying. next we feed |
| # the generated sources as a target to our dummy lib. Since they are not .c/.cpp files they are required to be there but |
| # result in no action. The generated archives will be empty, i.e: nm -a archives/libSWIFTSHADER_DEPENDENCIES.a |
| # |
| # dummy.c.o: 0000000000000000 a dummy.c |
| # |
| # Now this target can be used by others to take a dependency on. So we get: 1. Fast rebuilds (as we use ninja/make file |
| # out sync detection) 2. Binplace only once per dependency (no more concurrency problems) 3. No more target dependent |
| # binplacing (i.e. if a target does not end up in the root) which likely breaks the xcode generator. |
| function(android_target_dependency RUN_TARGET TARGET_TAG RUN_TARGET_DEPENDENCIES) |
| if(TARGET_TAG STREQUAL "${ANDROID_TARGET_TAG}" OR TARGET_TAG STREQUAL "all") |
| |
| # Link to existing target if there. |
| if(TARGET ${RUN_TARGET_DEPENDENCIES}) |
| target_link_libraries(${RUN_TARGET} PRIVATE ${RUN_TARGET_DEPENDENCIES}) |
| return() |
| endif() |
| |
| # Okay let's construct our target. |
| add_library(${RUN_TARGET_DEPENDENCIES} ${ANDROID_QEMU2_TOP_DIR}/dummy.c) |
| |
| set(DEPENDENCIES "${${RUN_TARGET_DEPENDENCIES}}") |
| set(DEP_SOURCES "") |
| list(REMOVE_DUPLICATES DEPENDENCIES) |
| foreach(DEP ${DEPENDENCIES}) |
| # Are we copying a directory or a file? |
| if(DEP MATCHES ".*>>.*") |
| string(REPLACE ">>" ";" SRC_DST ${DEP}) |
| list(GET SRC_DST 0 SRC) |
| list(GET SRC_DST 1 DST) |
| file(GLOB GLOBBED ${SRC}) |
| if(NOT GLOBBED) |
| message( |
| FATAL_ERROR |
| "The target ${RUN_TARGET} depends on a dependency: [${SRC}]/[${GLOBBED}] that does not exist. Full list ${RUN_TARGET_DEPENDENCIES}!" |
| ) |
| endif() |
| |
| # Let's calculate the destination directory, so we can use this as our generated sources parameters. |
| get_filename_component(SRC_DIR "${SRC}" DIRECTORY) |
| set(DEST_SRC "") |
| set(DEST_DIR "${CMAKE_BINARY_DIR}/${DST}") |
| foreach(FNAME ${GLOBBED}) |
| string(REPLACE "${SRC_DIR}" "${DEST_DIR}" DEST_FILE "${FNAME}") |
| android_binplace(${RUN_TARGET_DEPENDENCIES} ${FNAME} ${DEST_FILE}) |
| endforeach() |
| else() |
| # We are doing single file copies. Turns src>dst into a list, so we can split out SRC --> DST |
| string(REPLACE ">" ";" SRC_DST ${DEP}) |
| list(GET SRC_DST 0 SRC) |
| list(GET SRC_DST 1 DST) |
| set(DEST_FILE "${CMAKE_BINARY_DIR}/${DST}") |
| android_binplace(${RUN_TARGET_DEPENDENCIES} ${SRC} ${DEST_FILE}) |
| endif() |
| endforeach() |
| target_link_libraries(${RUN_TARGET} PRIVATE ${RUN_TARGET_DEPENDENCIES}) |
| endif() |
| endfunction() |
| |
| # Add the runtime dependencies, i.e. the set of libs that need to be copied over to the proper location in order to run |
| # the executable. |
| # |
| # RUN_TARGET The executable that needs these run time dependencies |
| # |
| # TARGET_TAG The android target tag for which these are applicable, or all for all targets. |
| # |
| # RUN_TARGET_PROPERTIES List of properties that should be set on the target in order for it to properly link and run |
| # with the prebuilt dependency. For example LINK=--nmagic. Will set the linker flag --nmagic during compilation. |
| function(android_target_properties RUN_TARGET TARGET_TAG RUN_TARGET_PROPERTIES) |
| if(TARGET_TAG STREQUAL "${ANDROID_TARGET_TAG}" OR TARGET_TAG STREQUAL "all") |
| foreach(PROP ${RUN_TARGET_PROPERTIES}) |
| if(PROP MATCHES ".*>=.*") |
| # We are appending |
| string(REPLACE ">=" ";" KEY_VAL ${PROP}) |
| list(GET KEY_VAL 0 KEY) |
| list(GET KEY_VAL 1 VAL) |
| # Note we are not treating the propery as a list! |
| get_property(CURR_VAL TARGET ${RUN_TARGET} PROPERTY ${KEY}) |
| # Of course we deal with lists differently on different platforms! |
| if(APPLE) |
| set_property(TARGET ${RUN_TARGET} PROPERTY "${KEY}" ${CURR_VAL};${VAL}) |
| android_log("set_property(TARGET ${RUN_TARGET} PROPERTY '${KEY}' ${CURR_VAL};${VAL})") |
| else() |
| set_property(TARGET ${RUN_TARGET} PROPERTY "${KEY}" "${CURR_VAL} ${VAL}") |
| android_log("set_property(TARGET ${RUN_TARGET} PROPERTY '${KEY}' ${CURR_VAL} ${VAL})") |
| endif() |
| else() |
| # We are replacing |
| string(REPLACE "=" ";" KEY_VAL ${PROP}) |
| list(GET KEY_VAL 0 KEY) |
| list(GET KEY_VAL 1 VAL) |
| set_property(TARGET ${RUN_TARGET} PROPERTY "${KEY}" "${VAL}") |
| android_log("set_property(TARGET ${RUN_TARGET} PROPERTY '${KEY}' '${VAL}')") |
| endif() |
| endforeach() |
| endif() |
| endfunction() |