Skip to content

Commit

Permalink
Build macOS framework and add CocoaPods podspec (facebook#285)
Browse files Browse the repository at this point in the history
Summary:
Supersedes facebook#239

Currently used in our macOS fork of React Native microsoft/react-native-macos#473. (Although we’re using a build of Hermes v0.4.1, as we’re at RN 0.62.0.)

* On Apple platforms build a [dynamic] framework bundle when `HERMES_BUILD_APPLE_FRAMEWORK` is set. When set to `FALSE` it will produce a `dylib`, like previously. Defaults to `TRUE`.
* On Apple platforms create a debugging symbols bundle.
* Add `HERMES_ENABLE_FUZZING`, which is enabled by default.
* Add `HERMES_ENABLE_TEST_SUITE`, which is enabled by default.
* Add a CocoaPods podspec that can build from source or use a binary.

A standalone macOS app that pulls in Hermes as a CocoaPods pod can be found here https://github.com/alloy/TestHermesMaster.

## Framework variant (default)

```
$ ./src/utils/build/configure.py --distribute --cmake-flags='-DCMAKE_INSTALL_PREFIX:PATH=../destroot_release' build
$ cd build && ninja install && cd ..
$ tree destroot_release/
destroot_release/
├── Library
│   └── Frameworks
│       ├── hermes.framework
│       │   ├── Headers -> Versions/Current/Headers
│       │   ├── Resources -> Versions/Current/Resources
│       │   ├── Versions
│       │   │   ├── 0
│       │   │   │   ├── Headers
│       │   │   │   │   ├── CompileJS.h
│       │   │   │   │   ├── DebuggerAPI.h
│       │   │   │   │   ├── Public
│       │   │   │   │   │   ├── Buffer.h
│       │   │   │   │   │   ├── CrashManager.h
│       │   │   │   │   │   ├── CtorConfig.h
│       │   │   │   │   │   ├── DebuggerTypes.h
│       │   │   │   │   │   ├── GCConfig.h
│       │   │   │   │   │   ├── GCTripwireContext.h
│       │   │   │   │   │   └── RuntimeConfig.h
│       │   │   │   │   ├── SynthTrace.h
│       │   │   │   │   ├── SynthTraceParser.h
│       │   │   │   │   ├── TraceInterpreter.h
│       │   │   │   │   ├── TracingRuntime.h
│       │   │   │   │   ├── hermes.h
│       │   │   │   │   └── hermes_tracing.h
│       │   │   │   ├── Resources
│       │   │   │   │   └── Info.plist
│       │   │   │   └── hermes
│       │   │   └── Current -> 0
│       │   └── hermes -> Versions/Current/hermes
│       └── hermes.framework.dSYM
│           └── Contents
│               ├── Info.plist
│               └── Resources
│                   └── DWARF
│                       └── hermes
├── bin
│   ├── hbcdump
│   ├── hdb
│   ├── hermes
│   ├── hermesc
│   └── hvm
└── include
    ├── hermes
    │   ├── CompileJS.h
    │   ├── DebuggerAPI.h
    │   ├── Public
    │   │   ├── Buffer.h
    │   │   ├── CrashManager.h
    │   │   ├── CtorConfig.h
    │   │   ├── DebuggerTypes.h
    │   │   ├── GCConfig.h
    │   │   ├── GCTripwireContext.h
    │   │   └── RuntimeConfig.h
    │   ├── SynthTrace.h
    │   ├── SynthTraceParser.h
    │   ├── TraceInterpreter.h
    │   ├── TracingRuntime.h
    │   ├── hermes.h
    │   └── hermes_tracing.h
    └── jsi
        ├── JSIDynamic.h
        ├── decorator.h
        ├── instrumentation.h
        ├── jsi-inl.h
        ├── jsi.h
        ├── jsilib.h
        └── threadsafe.h
```

# dylib variant

```
$ ./src/utils/build/configure.py --distribute --cmake-flags='-DHERMES_BUILD_APPLE_FRAMEWORK:BOOLEAN=false -DCMAKE_INSTALL_PREFIX:PATH=../destroot_release' build
$ cd build && ninja install && cd ..
$ tree destroot_release/
destroot_release/
├── bin
│   ├── hbcdump
│   ├── hdb
│   ├── hermes
│   ├── hermesc
│   └── hvm
├── include
│   ├── hermes
│   │   ├── CompileJS.h
│   │   ├── DebuggerAPI.h
│   │   ├── Public
│   │   │   ├── Buffer.h
│   │   │   ├── CrashManager.h
│   │   │   ├── CtorConfig.h
│   │   │   ├── DebuggerTypes.h
│   │   │   ├── GCConfig.h
│   │   │   ├── GCTripwireContext.h
│   │   │   └── RuntimeConfig.h
│   │   ├── SynthTrace.h
│   │   ├── SynthTraceParser.h
│   │   ├── TraceInterpreter.h
│   │   ├── TracingRuntime.h
│   │   ├── hermes.h
│   │   └── hermes_tracing.h
│   └── jsi
│       ├── JSIDynamic.h
│       ├── decorator.h
│       ├── instrumentation.h
│       ├── jsi-inl.h
│       ├── jsi.h
│       ├── jsilib.h
│       └── threadsafe.h
└── lib
    ├── libhermes.dylib
    └── libhermes.dylib.dSYM
        └── Contents
            ├── Info.plist
            └── Resources
                └── DWARF
                    └── libhermes.dylib
```

Pull Request resolved: facebook#285

Reviewed By: willholen

Differential Revision: D22398354

Pulled By: mhorowitz

fbshipit-source-id: 732524275cf273866171fc6e2ac2acb062185fbd
  • Loading branch information
alloy authored and facebook-github-bot committed Jul 9, 2020
1 parent e4f9df4 commit a9b5645
Show file tree
Hide file tree
Showing 30 changed files with 1,532 additions and 75 deletions.
23 changes: 22 additions & 1 deletion .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ workflows:
- windows
- test-linux
- test-macos
- test-macos-podspec
- test-e2e:
requires:
- npm
Expand Down Expand Up @@ -253,13 +254,33 @@ jobs:
cmake --build ./build
cmake --build ./build --target check-hermes
test-macos-podspec:
macos:
xcode: "10.3.0"
environment:
- TERM: dumb
# Homebrew currently breaks while updating:
# https://discuss.circleci.com/t/brew-install-fails-while-updating/32992
- HOMEBREW_NO_AUTO_UPDATE: 1
steps:
- checkout
- run:
name: Install dependencies
command: |
brew install cmake ninja
- run:
name: Run CocoaPods installation and test framework
command: |
cd test/ApplePlatformsIntegrationTestApp
./run.sh
windows:
executor:
name: win/preview-default
shell: powershell.exe
environment:
- HERMES_WS_DIR: 'C:\tmp\hermes'
- ICU_URL: 'https://github.com/unicode-org/icu/releases/download/release-64-2/icu4c-64_2-Win64-MSVC2017.zip'
- ICU_URL: "https://github.com/unicode-org/icu/releases/download/release-64-2/icu4c-64_2-Win64-MSVC2017.zip"
- MSBUILD_DIR: 'C:\Program Files (x86)\Microsoft Visual Studio\2019\BuildTools\MSBuild\Current\Bin'
- CMAKE_DIR: 'C:\Program Files\CMake\bin'
steps:
Expand Down
8 changes: 8 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,11 @@ buck-out

# Mac
.DS_Store

# CocoaPods testing
build
destroot
test/ApplePlatformsIntegrationTestApp/Podfile.lock
test/ApplePlatformsIntegrationTestApp/Pods
test/ApplePlatformsIntegrationTestApp/**/xcuserdata
test/ApplePlatformsIntegrationTestApp/ApplePlatformsIntegrationTestApp.xcworkspace
68 changes: 66 additions & 2 deletions API/hermes/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ set(api_sources
DebuggerAPI.cpp
)

file(GLOB api_headers ${CMAKE_CURRENT_SOURCE_DIR}/*.h)
file(GLOB api_public_headers ${PROJECT_SOURCE_DIR}/public/hermes/Public/*.h)

if (HERMESVM_API_TRACE)
list(APPEND api_sources
hermes_tracing.cpp
Expand Down Expand Up @@ -63,12 +66,13 @@ add_hermes_library(compileJS STATIC CompileJS.cpp)
set(HERMES_ENABLE_EH ON)
set(HERMES_ENABLE_RTTI ON)

add_library(libhermes SHARED ${api_sources})
add_library(libhermes SHARED ${api_sources} ${api_headers} ${api_public_headers})
target_link_libraries(libhermes
jsi
hermesVMRuntime
${CORE_FOUNDATION}
)
hermes_link_icu(libhermes)

# Export the required header directory
target_include_directories(libhermes PUBLIC ..)
Expand Down Expand Up @@ -96,5 +100,65 @@ set_target_properties(libhermes PROPERTIES
CXX_STANDARD_REQUIRED 14
# Avoid becoming liblibhermes (and there's already a target called 'hermes')
OUTPUT_NAME hermes
)

if(APPLE AND HERMES_BUILD_APPLE_FRAMEWORK)
set_target_properties(libhermes PROPERTIES
FRAMEWORK TRUE
VERSION ${PROJECT_VERSION}
SOVERSION ${PROJECT_VERSION}
FRAMEWORK_VERSION ${PROJECT_VERSION_MAJOR}
MACOSX_FRAMEWORK_SHORT_VERSION_STRING ${PROJECT_VERSION}
MACOSX_FRAMEWORK_BUNDLE_VERSION ${PROJECT_VERSION}
MACOSX_FRAMEWORK_IDENTIFIER dev.hermesengine.${CMAKE_SYSTEM_NAME}
)
hermes_link_icu(libhermes)
# Install headers into `Headers` while keeping required directory structure
set_source_files_properties(${api_headers} PROPERTIES
MACOSX_PACKAGE_LOCATION Headers
)
set_source_files_properties(${api_public_headers} PROPERTIES
MACOSX_PACKAGE_LOCATION Headers/Public
)
endif()

install(TARGETS libhermes
RUNTIME DESTINATION bin
LIBRARY DESTINATION lib
ARCHIVE DESTINATION lib
FRAMEWORK DESTINATION Library/Frameworks
)
# Install headers into `include` while keeping required directory structure
install(DIRECTORY "${PROJECT_SOURCE_DIR}/API/hermes" DESTINATION include
FILES_MATCHING PATTERN "*.h"
PATTERN "synthtest" EXCLUDE)

# Create debug symbols (dSYM) bundle for Apple platform dylibs/frameworks
# Largely inspired by https://github.com/llvm/llvm-project/blob/6701993027f8af172d7ba697884459261b00e3c6/llvm/cmake/modules/AddLLVM.cmake#L1934-L1986
if(APPLE AND CMAKE_CXX_FLAGS MATCHES "-gdwarf")
if(CMAKE_CXX_FLAGS MATCHES "-flto")
set(lto_object ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/libhermes-lto.o)
set_property(TARGET libhermes APPEND_STRING PROPERTY LINK_FLAGS " -Wl,-object_path_lto,${lto_object}")
endif()

get_target_property(DSYM_PATH libhermes LOCATION)
if(HERMES_BUILD_APPLE_FRAMEWORK)
get_filename_component(DSYM_PATH ${DSYM_PATH} DIRECTORY)
endif()
set(DSYM_PATH "${DSYM_PATH}.dSYM")

if(NOT CMAKE_DSYMUTIL)
set(CMAKE_DSYMUTIL xcrun dsymutil)
endif()
add_custom_command(TARGET libhermes POST_BUILD
COMMAND ${CMAKE_DSYMUTIL} $<TARGET_FILE:libhermes> --out ${DSYM_PATH}
BYPRODUCTS ${DSYM_PATH}
)

if(HERMES_BUILD_APPLE_FRAMEWORK)
install(DIRECTORY ${DSYM_PATH} DESTINATION Library/Frameworks)
else()
install(DIRECTORY ${DSYM_PATH} DESTINATION lib)
endif()
endif()

hermes_strip_apple_debug_symbols(libhermes)
4 changes: 4 additions & 0 deletions API/jsi/jsi/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,7 @@ elseif ("${CMAKE_CXX_COMPILER_ID}" MATCHES "MSVC")
list(APPEND jsi_compile_flags "/EHsc")
endif()
target_compile_options(jsi PUBLIC ${jsi_compile_flags})

install(DIRECTORY "${PROJECT_SOURCE_DIR}/API/jsi/" DESTINATION include
FILES_MATCHING PATTERN "*.h"
PATTERN "test" EXCLUDE)
146 changes: 92 additions & 54 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,17 @@ if (POLICY CMP0023)
cmake_policy(SET CMP0023 OLD)
endif()

# Allow reading the LOCATION property of a target to determine the eventual
# location of build targets. This is needed when building the debugging symbols
# bundles for Apple platforms.
if (POLICY CMP0026)
cmake_policy(SET CMP0026 OLD)
endif()

# This must be consistent with the release_version in
# android/build.gradle and npm/package.json
# This must be consistent with the release_version in:
# - android/build.gradle
# - npm/package.json
# - hermes.podspec
project(Hermes
VERSION 0.5.0
LANGUAGES C CXX)
Expand Down Expand Up @@ -127,6 +135,9 @@ set(HERMES_ENABLE_ADDRESS_SANITIZER OFF CACHE BOOL
set(HERMES_ENABLE_UNDEFINED_BEHAVIOR_SANITIZER OFF CACHE BOOL
"Enable -fsanitize=undefined")

set(HERMES_ENABLE_FUZZING ON CACHE BOOL
"Enable fuzzing")

# Set linker flag for building the fuzzer
set(HERMES_FUZZING_FLAG "-fsanitize=fuzzer" CACHE STRING
"Linker argument to link fuzz targets against a given fuzzer.")
Expand Down Expand Up @@ -197,7 +208,17 @@ set(EMSCRIPTEN_FASTCOMP ON CACHE BOOL
set(HERMES_ENABLE_INTL OFF CACHE BOOL
"Enable JS Intl support (WIP)")

if (HERMES_IS_ANDROID)
set(HERMES_ENABLE_TEST_SUITE ON CACHE BOOL
"Enable the test suite")

set(HERMES_BUILD_APPLE_FRAMEWORK ON CACHE BOOL
"Whether to build the libhermes target as a framework bundle or dylib on Apple platforms")

if (NOT HERMES_IS_MOBILE_BUILD AND APPLE)
# Always emit debugging symbols (in the DWARF) format, as these will be
# stripped out of each target post-build.
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -gdwarf")
elseif (HERMES_IS_ANDROID)
set(HERMES_IS_MOBILE_BUILD TRUE)

add_definitions(-DHERMES_PLATFORM_UNICODE=HERMES_PLATFORM_UNICODE_JAVA)
Expand All @@ -218,7 +239,6 @@ if (HERMES_IS_ANDROID)
# https://github.com/android-ndk/ndk/issues/242
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -fuse-ld=gold")
endif()

endif()

if (HERMES_IS_MOBILE_BUILD)
Expand Down Expand Up @@ -486,6 +506,20 @@ function(hermes_link_icu target_name)
endif()
endfunction()

# Declare a function that strips debugging symbols from any target built for
# Apple platforms, which we do build initially so they can be extracted into a
# dSYM bundle.
function(hermes_strip_apple_debug_symbols target_name)
if(APPLE)
if(NOT CMAKE_STRIP)
set(CMAKE_STRIP xcrun strip)
endif()
add_custom_command(TARGET ${target_name} POST_BUILD
COMMAND ${CMAKE_STRIP} -S $<TARGET_FILE:${target_name}>
)
endif()
endfunction()

if (APPLE)
find_library(CORE_FOUNDATION CoreFoundation)
else()
Expand Down Expand Up @@ -566,8 +600,8 @@ add_subdirectory(utils/hermes-lit)
add_subdirectory(tools)
add_subdirectory(include)
add_subdirectory(lib)
add_subdirectory(public)
add_subdirectory(external)
add_subdirectory(unittests)
add_subdirectory(API)
add_subdirectory(android/intltest/java/com/facebook/hermes/test)

Expand All @@ -583,55 +617,59 @@ endif()

# Configure the test suites
#
list(APPEND HERMES_TEST_DEPS
HermesUnitTests
hermes
hermesc
hvm
interp-dispatch-bench
hdb
hbcdump
hbc-attribute
hbc-deltaprep
hbc-diff
dependency-extractor
)

set(HERMES_LIT_TEST_PARAMS
test_exec_root=${HERMES_BINARY_DIR}/test
unittests_dir=${HERMES_BINARY_DIR}/unittests
debugger_enabled=${HERMES_ENABLE_DEBUGGER}
use_flowparser=${HERMES_USE_FLOWPARSER}
jit_enabled=${HERMESVM_JIT}
jit_disassembler_enabled=${HERMESVM_JIT_DISASSEMBLER}
hbc_deltaprep=${HERMES_TOOLS_OUTPUT_DIR}/hbc-deltaprep
dependency_extractor=${HERMES_TOOLS_OUTPUT_DIR}/dependency-extractor
FileCheck=${HERMES_TOOLS_OUTPUT_DIR}//FileCheck
hermes=${HERMES_TOOLS_OUTPUT_DIR}/hermes
hermesc=${HERMES_TOOLS_OUTPUT_DIR}/hermesc
hdb=${HERMES_TOOLS_OUTPUT_DIR}/hdb
hbcdump=${HERMES_TOOLS_OUTPUT_DIR}/hbcdump
hbc-deltaprep=${HERMES_TOOLS_OUTPUT_DIR}/hbc-deltaprep
hbc_diff=${HERMES_TOOLS_OUTPUT_DIR}/hbc-diff
build_mode=${HERMES_ASSUMED_BUILD_MODE_IN_LIT_TEST}
exception_on_oom_enabled=${HERMESVM_EXCEPTION_ON_OOM}
serialize_enabled=${HERMESVM_SERIALIZE}
profiler=${HERMES_PROFILER_MODE_IN_LIT_TEST}
use_js_library_implementation=${HERMESVM_USE_JS_LIBRARY_IMPLEMENTATION}
gc=${HERMESVM_GCKIND}
ubsan=${HERMES_ENABLE_UNDEFINED_BEHAVIOR_SANITIZER}
)

set(LLVH_LIT_ARGS "-sv")

add_lit_testsuite(check-hermes "Running the Hermes regression tests"
${HERMES_SOURCE_DIR}/test
${HERMES_SOURCE_DIR}/unittests
PARAMS ${HERMES_LIT_TEST_PARAMS}
DEPENDS ${HERMES_TEST_DEPS}
ARGS ${HERMES_TEST_EXTRA_ARGS}
)
set_target_properties(check-hermes PROPERTIES FOLDER "Hermes regression tests")
if(HERMES_ENABLE_TEST_SUITE)
add_subdirectory(unittests)

list(APPEND HERMES_TEST_DEPS
HermesUnitTests
hermes
hermesc
hvm
interp-dispatch-bench
hdb
hbcdump
hbc-attribute
hbc-deltaprep
hbc-diff
dependency-extractor
)

set(HERMES_LIT_TEST_PARAMS
test_exec_root=${HERMES_BINARY_DIR}/test
unittests_dir=${HERMES_BINARY_DIR}/unittests
debugger_enabled=${HERMES_ENABLE_DEBUGGER}
use_flowparser=${HERMES_USE_FLOWPARSER}
jit_enabled=${HERMESVM_JIT}
jit_disassembler_enabled=${HERMESVM_JIT_DISASSEMBLER}
hbc_deltaprep=${HERMES_TOOLS_OUTPUT_DIR}/hbc-deltaprep
dependency_extractor=${HERMES_TOOLS_OUTPUT_DIR}/dependency-extractor
FileCheck=${HERMES_TOOLS_OUTPUT_DIR}//FileCheck
hermes=${HERMES_TOOLS_OUTPUT_DIR}/hermes
hermesc=${HERMES_TOOLS_OUTPUT_DIR}/hermesc
hdb=${HERMES_TOOLS_OUTPUT_DIR}/hdb
hbcdump=${HERMES_TOOLS_OUTPUT_DIR}/hbcdump
hbc-deltaprep=${HERMES_TOOLS_OUTPUT_DIR}/hbc-deltaprep
hbc_diff=${HERMES_TOOLS_OUTPUT_DIR}/hbc-diff
build_mode=${HERMES_ASSUMED_BUILD_MODE_IN_LIT_TEST}
exception_on_oom_enabled=${HERMESVM_EXCEPTION_ON_OOM}
serialize_enabled=${HERMESVM_SERIALIZE}
profiler=${HERMES_PROFILER_MODE_IN_LIT_TEST}
use_js_library_implementation=${HERMESVM_USE_JS_LIBRARY_IMPLEMENTATION}
gc=${HERMESVM_GCKIND}
ubsan=${HERMES_ENABLE_UNDEFINED_BEHAVIOR_SANITIZER}
)

set(LLVH_LIT_ARGS "-sv")

add_lit_testsuite(check-hermes "Running the Hermes regression tests"
${HERMES_SOURCE_DIR}/test
${HERMES_SOURCE_DIR}/unittests
PARAMS ${HERMES_LIT_TEST_PARAMS}
DEPENDS ${HERMES_TEST_DEPS}
ARGS ${HERMES_TEST_EXTRA_ARGS}
)
set_target_properties(check-hermes PROPERTIES FOLDER "Hermes regression tests")
endif()

# This is how github release files are built.

Expand Down
Loading

0 comments on commit a9b5645

Please sign in to comment.