From 01f66f7b04afdc6355a78c85557656ac33b23418 Mon Sep 17 00:00:00 2001 From: Sung-Jae Lee Date: Tue, 15 Sep 2015 09:43:03 +0900 Subject: [PATCH] Enable build on Mac OS X with clang * Add build target 'darwin' * Modify compiler options to work with clang * Support 'jerry-libc' on Mac OS X For MPU target build, install `gcc-arm-none-eabi` tool chain using `Homebrew` as following. ```` brew tap PX4/homebrew-px4 brew update brew install gcc-arm-none-eabi ```` https://pixhawk.org/dev/toolchain_installation_mac JerryScript-DCO-1.0-Signed-off-by: Sung-Jae Lee sjlee@mail.com --- CMakeLists.txt | 129 +++++-- Makefile | 35 +- build/configs/toolchain_darwin_x86_64.cmake | 23 ++ jerry-libc/CMakeLists.txt | 8 + jerry-libc/target/darwin/jerry-asm.S | 56 +++ jerry-libc/target/darwin/jerry-libc-target.c | 386 +++++++++++++++++++ main-darwin.cpp | 319 +++++++++++++++ 7 files changed, 903 insertions(+), 53 deletions(-) create mode 100644 build/configs/toolchain_darwin_x86_64.cmake create mode 100644 jerry-libc/target/darwin/jerry-asm.S create mode 100644 jerry-libc/target/darwin/jerry-libc-target.c create mode 100644 main-darwin.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 116e81f08..33ffac90d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -15,28 +15,35 @@ cmake_minimum_required (VERSION 2.8.12) project (Jerry CXX C ASM) -# Require g++ of version >= 4.7.0 - if(NOT CMAKE_COMPILER_IS_GNUCXX) - message(FATAL_ERROR "g++ compiler is required") - else() - execute_process(COMMAND ${CMAKE_CXX_COMPILER} -dumpversion - OUTPUT_VARIABLE GNU_CXX_VERSION - OUTPUT_STRIP_TRAILING_WHITESPACE) +# Determining platform + set(PLATFORM "${CMAKE_SYSTEM_NAME}") + string(TOUPPER "${PLATFORM}" PLATFORM) - if(${GNU_CXX_VERSION} VERSION_LESS 4.7.0) - message(FATAL_ERROR "g++ compiler version 4.7.0 or higher required") - endif() +# Compiler configuration + if(NOT ("${PLATFORM}" STREQUAL "DARWIN")) + # Require g++ of version >= 4.7.0 + if(NOT CMAKE_COMPILER_IS_GNUCXX) + message(FATAL_ERROR "g++ compiler is required") + else() + execute_process(COMMAND ${CMAKE_CXX_COMPILER} -dumpversion + OUTPUT_VARIABLE GNU_CXX_VERSION + OUTPUT_STRIP_TRAILING_WHITESPACE) + + if(${GNU_CXX_VERSION} VERSION_LESS 4.7.0) + message(FATAL_ERROR "g++ compiler version 4.7.0 or higher required") + endif() + endif() + + # Use gcc-ar and gcc-ranlib to support LTO + get_filename_component(PATH_TO_GCC ${CMAKE_C_COMPILER} REALPATH) + get_filename_component(DIRECTORY_GCC ${PATH_TO_GCC} DIRECTORY) + get_filename_component(FILE_NAME_GCC ${PATH_TO_GCC} NAME) + string(REPLACE "gcc" "gcc-ar" CMAKE_AR ${FILE_NAME_GCC}) + string(REPLACE "gcc" "gcc-ranlib" CMAKE_RANLIB ${FILE_NAME_GCC}) + set(CMAKE_AR ${DIRECTORY_GCC}/${CMAKE_AR}) + set(CMAKE_RANLIB ${DIRECTORY_GCC}/${CMAKE_RANLIB}) endif() -# Use gcc-ar and gcc-ranlib to support LTO - get_filename_component(PATH_TO_GCC ${CMAKE_C_COMPILER} REALPATH) - get_filename_component(DIRECTORY_GCC ${PATH_TO_GCC} DIRECTORY) - get_filename_component(FILE_NAME_GCC ${PATH_TO_GCC} NAME) - string(REPLACE "gcc" "gcc-ar" CMAKE_AR ${FILE_NAME_GCC}) - string(REPLACE "gcc" "gcc-ranlib" CMAKE_RANLIB ${FILE_NAME_GCC}) - set(CMAKE_AR ${DIRECTORY_GCC}/${CMAKE_AR}) - set(CMAKE_RANLIB ${DIRECTORY_GCC}/${CMAKE_RANLIB}) - # Imported and third-party targets prefix set(PREFIX_IMPORTED_LIB imported_) set(SUFFIX_THIRD_PARTY_LIB .third_party.lib) @@ -58,18 +65,20 @@ project (Jerry CXX C ASM) set(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS ) set(CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS ) -# Determining platform and defining options +# Defining options option(ENABLE_VALGRIND "Enable valgrind helpers in memory allocators" OFF) option(ENABLE_LTO "Enable LTO build" ON) option(ENABLE_LOG "Enable LOG build" OFF) - set(PLATFORM "${CMAKE_SYSTEM_NAME}") - string(TOUPPER "${PLATFORM}" PLATFORM) - if("${PLATFORM}" STREQUAL "LINUX") set(PLATFORM_EXT "LINUX") set(EXTERNAL_BUILD FALSE) + option(STRIP_RELEASE_BINARY "Strip symbols from release binaries" ON) + elseif("${PLATFORM}" STREQUAL "DARWIN") + set(PLATFORM_EXT "DARWIN") + set(EXTERNAL_BUILD FALSE) + option(STRIP_RELEASE_BINARY "Strip symbols from release binaries" ON) elseif("${PLATFORM}" STREQUAL "MCU") set(PLATFORM_EXT "MCU_${CMAKE_SYSTEM_VERSION}") @@ -167,6 +176,15 @@ project (Jerry CXX C ASM) "FULL_PROFILE MEMORY_STATISTICS" "COMPACT_PROFILE_MINIMAL MEMORY_STATISTICS") + # Darwin + set(MODIFIERS_LISTS_DARWIN + "FULL_PROFILE" + "FULL_PROFILE MEM_STRESS_TEST" + "COMPACT_PROFILE" + "COMPACT_PROFILE_MINIMAL" + "FULL_PROFILE MEMORY_STATISTICS" + "COMPACT_PROFILE_MINIMAL MEMORY_STATISTICS") + # MCU # stm32f3 set(MODIFIERS_LISTS_MCU_STM32F3 @@ -190,7 +208,10 @@ project (Jerry CXX C ASM) # Compiler / Linker flags set(COMPILE_FLAGS_JERRY "-fno-builtin") - set(LINKER_FLAGS_COMMON "-Wl,-z,noexecstack") + if(NOT ("${PLATFORM}" STREQUAL "DARWIN")) + set(LINKER_FLAGS_COMMON "-Wl,-z,noexecstack") + endif() + set(LINKER_FLAGS_COMMON_DARWIN "-lSystem") # Turn off linking to compiler's default libc, in case jerry-libc is used if(${USE_JERRY_LIBC}) @@ -199,7 +220,10 @@ project (Jerry CXX C ASM) # LTO if("${ENABLE_LTO}" STREQUAL "ON") - set(COMPILE_FLAGS_JERRY "${COMPILE_FLAGS_JERRY} -flto -fno-fat-lto-objects") + set(COMPILE_FLAGS_JERRY "${COMPILE_FLAGS_JERRY} -flto") + if(NOT ("${PLATFORM}" STREQUAL "DARWIN")) + set(COMPILE_FLAGS_JERRY "${COMPILE_FLAGS_JERRY} -fno-fat-lto-objects") + endif() set(LINKER_FLAGS_COMMON "${LINKER_FLAGS_COMMON} -flto") endif() @@ -210,20 +234,28 @@ project (Jerry CXX C ASM) set(COMPILE_FLAGS_JERRY "${COMPILE_FLAGS_JERRY} -g -gdwarf-4") # Warnings - set(COMPILE_FLAGS_JERRY "${COMPILE_FLAGS_JERRY} -Wall -Wextra -pedantic -Wlogical-op") + set(COMPILE_FLAGS_JERRY "${COMPILE_FLAGS_JERRY} -Wall -Wextra -pedantic") set(COMPILE_FLAGS_JERRY "${COMPILE_FLAGS_JERRY} -Wformat-nonliteral -Winit-self -Wno-stack-protector") set(COMPILE_FLAGS_JERRY "${COMPILE_FLAGS_JERRY} -Wconversion -Wsign-conversion -Wformat-security") set(COMPILE_FLAGS_JERRY "${COMPILE_FLAGS_JERRY} -Wmissing-declarations -Wno-attributes") - set(COMPILE_FLAGS_JERRY "${COMPILE_FLAGS_JERRY} -Werror -Wfatal-errors") + set(COMPILE_FLAGS_JERRY "${COMPILE_FLAGS_JERRY} -Wfatal-errors") + if(CMAKE_COMPILER_IS_GNUCXX) + set(COMPILE_FLAGS_JERRY "${COMPILE_FLAGS_JERRY} -Werror -Wlogical-op") + else() + set(COMPILE_FLAGS_JERRY "${COMPILE_FLAGS_JERRY} -Wno-nested-anon-types") + endif() # Static build - set(LINKER_FLAGS_STATIC "-static") + if(NOT ("${PLATFORM}" STREQUAL "DARWIN")) + set(LINKER_FLAGS_STATIC "-static") + endif() # C++ set(CXX_FLAGS_JERRY "-std=c++11 -fno-exceptions -fno-rtti") - # Turn off implicit template instantiation - set(CXX_FLAGS_JERRY "${CXX_FLAGS_JERRY} -fno-implicit-templates -fno-implicit-inline-templates") + if(CMAKE_COMPILER_IS_GNUCXX) + set(CXX_FLAGS_JERRY "${CXX_FLAGS_JERRY} -fno-implicit-templates -fno-implicit-inline-templates") + endif() # C set(C_FLAGS_JERRY "-std=c99") @@ -255,6 +287,9 @@ project (Jerry CXX C ASM) # Linux set(SOURCE_JERRY_STANDALONE_MAIN_LINUX main-linux.cpp) + # Darwin + set(SOURCE_JERRY_STANDALONE_MAIN_DARWIN main-darwin.cpp) + # MCU # stm32f3 set(SOURCE_JERRY_STANDALONE_MAIN_MCU_STM32F3 main-mcu.cpp) @@ -266,6 +301,16 @@ project (Jerry CXX C ASM) file(GLOB SOURCE_UNIT_TEST_MAIN_MODULES tests/unit/*.cpp) # Imported libraries +if(("${PLATFORM}" STREQUAL "DARWIN") AND (NOT CMAKE_COMPILER_IS_GNUCXX)) + # libclang_rt.osx + add_library(${PREFIX_IMPORTED_LIB}libclang_rt.osx STATIC IMPORTED) + execute_process(COMMAND ${CMAKE_C_COMPILER} ${FLAGS_COMMON_ARCH} -print-file-name= + OUTPUT_VARIABLE IMPORTED_LIBCLANG_RT_LOCATION + OUTPUT_STRIP_TRAILING_WHITESPACE) + set(IMPORTED_LIBCLANG_RT_LOCATION "${IMPORTED_LIBCLANG_RT_LOCATION}/lib/darwin/libclang_rt.osx.a") + set_property(TARGET ${PREFIX_IMPORTED_LIB}libclang_rt.osx + PROPERTY IMPORTED_LOCATION ${IMPORTED_LIBCLANG_RT_LOCATION}) +else() # libgcc add_library(${PREFIX_IMPORTED_LIB}libgcc STATIC IMPORTED) execute_process(COMMAND ${CMAKE_C_COMPILER} ${FLAGS_COMMON_ARCH} -print-file-name=libgcc.a @@ -286,6 +331,7 @@ project (Jerry CXX C ASM) set_property(TARGET ${PREFIX_IMPORTED_LIB}libgcc_eh PROPERTY IMPORTED_LOCATION ${IMPORTED_LIBGCC_LOCATION}) endif() +endif() # Platform-specific configuration set(MODIFIERS_LISTS ${MODIFIERS_LISTS_${PLATFORM_EXT}}) @@ -335,7 +381,7 @@ project (Jerry CXX C ASM) WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) add_custom_target(mcu_header_with_script_to_run.${TARGET_NAME} DEPENDS ${MCU_SCRIPT_GENERATED_HEADER}) set(DEFINES_JERRY ${DEFINES_JERRY} JERRY_MCU_SCRIPT_HEADER="${MCU_SCRIPT_GENERATED_HEADER}") - elseif("${PLATFORM}" STREQUAL "LINUX") + elseif(("${PLATFORM}" STREQUAL "LINUX") OR ("${PLATFORM}" STREQUAL "DARWIN")) if("${ENABLE_LOG}" STREQUAL "ON") set(DEFINES_JERRY ${DEFINES_JERRY} JERRY_ENABLE_LOG) endif() @@ -349,8 +395,13 @@ project (Jerry CXX C ASM) target_include_directories(${TARGET_NAME} PRIVATE ${INCLUDE_CORE_INTERFACE}) target_include_directories(${TARGET_NAME} SYSTEM PRIVATE ${INCLUDE_LIBC_INTERFACE}) target_include_directories(${TARGET_NAME} SYSTEM PRIVATE ${INCLUDE_EXTERNAL_LIBS_INTERFACE}) - target_link_libraries(${TARGET_NAME} ${CORE_TARGET_NAME} ${LIBC_TARGET_NAME} - ${FDLIBM_TARGET_NAME} ${PREFIX_IMPORTED_LIB}libgcc ${PREFIX_IMPORTED_LIB}libgcc_eh) + if(("${PLATFORM}" STREQUAL "DARWIN") AND (NOT CMAKE_COMPILER_IS_GNUCXX)) + target_link_libraries(${TARGET_NAME} ${CORE_TARGET_NAME} ${LIBC_TARGET_NAME} + ${FDLIBM_TARGET_NAME} ${PREFIX_IMPORTED_LIB}libclang_rt.osx) + else() + target_link_libraries(${TARGET_NAME} ${CORE_TARGET_NAME} ${LIBC_TARGET_NAME} + ${FDLIBM_TARGET_NAME} ${PREFIX_IMPORTED_LIB}libgcc ${PREFIX_IMPORTED_LIB}libgcc_eh) + endif() add_cppcheck_target(${TARGET_NAME}) @@ -403,7 +454,7 @@ project (Jerry CXX C ASM) declare_targets_for_build_mode(RELEASE) # Unit tests declaration - if("${PLATFORM}" STREQUAL "LINUX") + if(("${PLATFORM}" STREQUAL "LINUX") OR ("${PLATFORM}" STREQUAL "DARWIN")) add_custom_target(unittests) add_custom_target(cppcheck.unittests) @@ -424,8 +475,14 @@ project (Jerry CXX C ASM) PROPERTY LINK_FLAGS "${COMPILE_FLAGS_JERRY} ${CXX_FLAGS_JERRY} ${FLAGS_COMMON_UNITTESTS} ${LINKER_FLAGS_COMMON}") target_include_directories(${TARGET_NAME} PRIVATE ${INCLUDE_CORE_INTERFACE}) target_include_directories(${TARGET_NAME} SYSTEM PRIVATE ${INCLUDE_LIBC_INTERFACE}) - target_link_libraries(${TARGET_NAME} ${CORE_TARGET_NAME} ${LIBC_TARGET_NAME} ${FDLIBM_TARGET_NAME} - ${PREFIX_IMPORTED_LIB}libgcc ${PREFIX_IMPORTED_LIB}libgcc_eh) + + if(("${PLATFORM}" STREQUAL "DARWIN") AND (NOT CMAKE_COMPILER_IS_GNUCXX)) + target_link_libraries(${TARGET_NAME} ${CORE_TARGET_NAME} ${LIBC_TARGET_NAME} ${FDLIBM_TARGET_NAME} + ${PREFIX_IMPORTED_LIB}libclang_rt.osx) + else() + target_link_libraries(${TARGET_NAME} ${CORE_TARGET_NAME} ${LIBC_TARGET_NAME} ${FDLIBM_TARGET_NAME} + ${PREFIX_IMPORTED_LIB}libgcc ${PREFIX_IMPORTED_LIB}libgcc_eh) + endif() add_cppcheck_target(${TARGET_NAME}) diff --git a/Makefile b/Makefile index 1ba82dfa3..e04402521 100644 --- a/Makefile +++ b/Makefile @@ -15,7 +15,7 @@ # # Target naming scheme # -# Main targets: {debug,release}.{linux,stm32f{4}}[.flash] +# Main targets: {debug,release}.{linux,darwin,stm32f{4}}[.flash] # # Target mode part (before dot): # debug: - JERRY_NDEBUG; - optimizations; + debug symbols; + -Werror | debug build @@ -23,10 +23,11 @@ # # Target system and modifiers part (after first dot): # linux - target system is linux +# darwin - target system is Mac OS X # mcu_stm32f{3,4} - target is STM32F{3,4} board # # Modifiers can be added after '-' sign. -# For list of modifiers for PC target - see TARGET_PC_MODS, for MCU target - TARGET_MCU_MODS. +# For list of modifiers for NATIVE target - see TARGET_NATIVE_MODS, for MCU target - TARGET_MCU_MODS. # # Target action part (optional, after second dot): # flash - flash specified mcu target binary @@ -77,6 +78,8 @@ QLOG := >/dev/null endif +export TARGET_NATIVE_SYSTEMS = $(shell uname -s | tr [:upper:] [:lower:]) + # External build configuration # Flag, indicating whether to use compiler's default libc (YES / NO) USE_COMPILER_DEFAULT_LIBC ?= NO @@ -95,30 +98,28 @@ export TARGET_DEBUG_MODES = debug export TARGET_RELEASE_MODES = release -export TARGET_PC_SYSTEMS = linux - -export TARGET_PC_MODS = cp cp_minimal mem_stats mem_stress_test +export TARGET_NATIVE_MODS = cp cp_minimal mem_stats mem_stress_test export TARGET_MCU_MODS = cp cp_minimal -export TARGET_PC_SYSTEMS_MODS = $(TARGET_PC_SYSTEMS) \ - $(foreach __MOD,$(TARGET_PC_MODS),$(foreach __SYSTEM,$(TARGET_PC_SYSTEMS),$(__SYSTEM)-$(__MOD))) +export TARGET_NATIVE_SYSTEMS_MODS = $(TARGET_NATIVE_SYSTEMS) \ + $(foreach __MOD,$(TARGET_NATIVE_MODS),$(foreach __SYSTEM,$(TARGET_NATIVE_SYSTEMS),$(__SYSTEM)-$(__MOD))) export TARGET_STM32F3_MODS = $(foreach __MOD,$(TARGET_MCU_MODS),mcu_stm32f3-$(__MOD)) export TARGET_STM32F4_MODS = $(foreach __MOD,$(TARGET_MCU_MODS),mcu_stm32f4-$(__MOD)) # Target list -export JERRY_LINUX_TARGETS = $(foreach __MODE,$(TARGET_DEBUG_MODES),$(foreach __SYSTEM,$(TARGET_PC_SYSTEMS_MODS),$(__MODE).$(__SYSTEM))) \ - $(foreach __MODE,$(TARGET_RELEASE_MODES),$(foreach __SYSTEM,$(TARGET_PC_SYSTEMS_MODS),$(__MODE).$(__SYSTEM))) +export JERRY_NATIVE_TARGETS = $(foreach __MODE,$(TARGET_DEBUG_MODES),$(foreach __SYSTEM,$(TARGET_NATIVE_SYSTEMS_MODS),$(__MODE).$(__SYSTEM))) \ + $(foreach __MODE,$(TARGET_RELEASE_MODES),$(foreach __SYSTEM,$(TARGET_NATIVE_SYSTEMS_MODS),$(__MODE).$(__SYSTEM))) export JERRY_STM32F3_TARGETS = $(foreach __MODE,$(TARGET_RELEASE_MODES),$(foreach __SYSTEM,$(TARGET_STM32F3_MODS),$(__MODE).$(__SYSTEM))) export JERRY_STM32F4_TARGETS = $(foreach __MODE,$(TARGET_DEBUG_MODES),$(foreach __SYSTEM,$(TARGET_STM32F4_MODS),$(__MODE).$(__SYSTEM))) \ $(foreach __MODE,$(TARGET_RELEASE_MODES),$(foreach __SYSTEM,$(TARGET_STM32F4_MODS),$(__MODE).$(__SYSTEM))) -export JERRY_TARGETS = $(JERRY_LINUX_TARGETS) $(JERRY_STM32F3_TARGETS) $(JERRY_STM32F4_TARGETS) unittests +export JERRY_TARGETS = $(JERRY_NATIVE_TARGETS) $(JERRY_STM32F3_TARGETS) $(JERRY_STM32F4_TARGETS) unittests -export CHECK_TARGETS = $(foreach __TARGET,$(JERRY_LINUX_TARGETS),$(__TARGET).check) +export CHECK_TARGETS = $(foreach __TARGET,$(JERRY_NATIVE_TARGETS),$(__TARGET).check) export FLASH_TARGETS = $(foreach __TARGET,$(JERRY_STM32F3_TARGETS) $(JERRY_STM32F4_TARGETS),$(__TARGET).flash) export OUT_DIR = ./build/bin @@ -127,7 +128,7 @@ export PREREQUISITES_STATE_DIR = ./build/prerequisites export SHELL=/bin/bash # Precommit check targets - PRECOMMIT_CHECK_TARGETS_LIST := debug.linux release.linux + PRECOMMIT_CHECK_TARGETS_LIST := debug.$(TARGET_NATIVE_SYSTEMS) release.$(TARGET_NATIVE_SYSTEMS) # Building all options combinations OPTIONS_COMBINATIONS := $(foreach __OPTION,ON OFF,$(__COMBINATION)-VALGRIND-$(__OPTION)) @@ -167,7 +168,7 @@ $(BUILD_DIRS_NATIVE): then \ readelf -A /proc/self/exe | grep Tag_ABI_VFP_args && arch=$$arch"-hf" || arch=$$arch"-el"; \ fi; \ - TOOLCHAIN="build/configs/toolchain_linux_$$arch.cmake"; \ + TOOLCHAIN="build/configs/toolchain_$(TARGET_NATIVE_SYSTEMS)_$$arch.cmake"; \ fi; \ if [ -d "$@" ]; \ then \ @@ -198,8 +199,8 @@ $(BUILD_DIRS_STM32F4): prerequisites (cmake -DENABLE_VALGRIND=$(VALGRIND) -DENABLE_LTO=$(LTO) -DCMAKE_TOOLCHAIN_FILE=build/configs/toolchain_mcu_stm32f4.cmake ../../.. 2>&1 | tee cmake.log $(QLOG) ; ( exit $${PIPESTATUS[0]} ) ) || \ (echo "CMake run failed. See "`pwd`"/cmake.log for details."; exit 1;) -.PHONY: $(JERRY_LINUX_TARGETS) -$(JERRY_LINUX_TARGETS): $(BUILD_DIR)/native +.PHONY: $(JERRY_NATIVE_TARGETS) +$(JERRY_NATIVE_TARGETS): $(BUILD_DIR)/native $(Q) mkdir -p $(OUT_DIR)/$@ $(Q) [ "$(STATIC_CHECK)" = "OFF" ] || ($(MAKE) -C $(BUILD_DIR)/native VERBOSE=1 cppcheck.$@ 2>&1 | tee $(OUT_DIR)/$@/cppcheck.log $(QLOG) ; ( exit $${PIPESTATUS[0]} ) ) || \ (echo "cppcheck run failed. See $(OUT_DIR)/$@/cppcheck.log for details."; exit 1;) @@ -219,11 +220,11 @@ unittests: $(BUILD_DIR)/native .PHONY: $(BUILD_ALL)_native $(BUILD_ALL)_native: $(BUILD_DIRS_NATIVE) $(Q) mkdir -p $(OUT_DIR)/$@ - $(Q) ($(MAKE) -C $(BUILD_DIR)/native jerry-libc-all VERBOSE=1 2>&1 | tee $(OUT_DIR)/$@/make.log $(QLOG) ; ( exit $${PIPESTATUS[0]} ) ) || \ + $(Q) [ "$(USE_COMPILER_DEFAULT_LIBC)" = "YES" ] || ($(MAKE) -C $(BUILD_DIR)/native jerry-libc-all VERBOSE=1 2>&1 | tee $(OUT_DIR)/$@/make.log $(QLOG) ; ( exit $${PIPESTATUS[0]} ) ) || \ (echo "Build failed. See $(OUT_DIR)/$@/make.log for details."; exit 1;) $(Q) ($(MAKE) -C $(BUILD_DIR)/native jerry-fdlibm-all VERBOSE=1 2>&1 | tee $(OUT_DIR)/$@/make.log $(QLOG) ; ( exit $${PIPESTATUS[0]} ) ) || \ (echo "Build failed. See $(OUT_DIR)/$@/make.log for details."; exit 1;) - $(Q) ($(MAKE) -C $(BUILD_DIR)/native $(JERRY_LINUX_TARGETS) unittests VERBOSE=1 2>&1 | tee $(OUT_DIR)/$@/make.log $(QLOG) ; ( exit $${PIPESTATUS[0]} ) ) || \ + $(Q) ($(MAKE) -C $(BUILD_DIR)/native $(JERRY_NATIVE_TARGETS) unittests VERBOSE=1 2>&1 | tee $(OUT_DIR)/$@/make.log $(QLOG) ; ( exit $${PIPESTATUS[0]} ) ) || \ (echo "Build failed. See $(OUT_DIR)/$@/make.log for details."; exit 1;) .PHONY: $(JERRY_STM32F3_TARGETS) diff --git a/build/configs/toolchain_darwin_x86_64.cmake b/build/configs/toolchain_darwin_x86_64.cmake new file mode 100644 index 000000000..95c1bfabb --- /dev/null +++ b/build/configs/toolchain_darwin_x86_64.cmake @@ -0,0 +1,23 @@ +# Copyright 2015 Samsung Electronics Co., Ltd. +# +# 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. + +set(CMAKE_SYSTEM_NAME Darwin) +set(CMAKE_SYSTEM_PROCESSOR x86_64) + +find_program(CMAKE_C_COMPILER NAMES cc) +find_program(CMAKE_CXX_COMPILER NAMES c++) +# FIXME: This could break cross compilation, when the strip is not for the target architecture +find_program(CMAKE_STRIP NAMES strip) + +#set(FLAGS_COMMON_ARCH -ffixed-rbp) diff --git a/jerry-libc/CMakeLists.txt b/jerry-libc/CMakeLists.txt index 19791eff2..adbc746af 100644 --- a/jerry-libc/CMakeLists.txt +++ b/jerry-libc/CMakeLists.txt @@ -40,6 +40,8 @@ set(COMPILE_FLAGS_LIBC "${COMPILE_FLAGS_JERRY} ${C_FLAGS_JERRY}") # Platform-specific # Linux set(DEFINES_LIBC_LINUX __TARGET_HOST) + # Darwin + set(DEFINES_LIBC_DARWIN __TARGET_HOST) # MCU set(DEFINES_LIBC_MCU __TARGET_MCU) # stm32f3 @@ -57,6 +59,9 @@ set(COMPILE_FLAGS_LIBC "${COMPILE_FLAGS_JERRY} ${C_FLAGS_JERRY}") # Linux set(INCLUDE_THIRD_PARTY_LINUX ) + # Darwin + set(INCLUDE_THIRD_PARTY_DARWIN ) + # MCU # STM32F3 set(INCLUDE_THIRD_PARTY_MCU_STM32F3 @@ -74,6 +79,9 @@ set(COMPILE_FLAGS_LIBC "${COMPILE_FLAGS_JERRY} ${C_FLAGS_JERRY}") # Linux file(GLOB SOURCE_LIBC_LINUX target/linux/*.c target/linux/*.S) + # Darwin + file(GLOB SOURCE_LIBC_DARWIN target/darwin/*.c target/darwin/*.S) + # MCU # stm32f3 file(GLOB SOURCE_LIBC_MCU_STM32F3 target/mcu-stubs/*.c target/mcu-stubs/*.S) diff --git a/jerry-libc/target/darwin/jerry-asm.S b/jerry-libc/target/darwin/jerry-asm.S new file mode 100644 index 000000000..7219f4fee --- /dev/null +++ b/jerry-libc/target/darwin/jerry-asm.S @@ -0,0 +1,56 @@ +#ifdef __TARGET_HOST_x64 +# include "arch/x86-64.h" +#elif defined (__TARGET_HOST_x86) +# include "arch/x86-32.h" +#elif defined (__TARGET_HOST_ARMv7) +# include "arch/arm-v7.h" +#else /* !__TARGET_HOST_x64 && !__TARGET_HOST_x86 && !__TARGET_HOST_ARMv7 */ +# error "!__TARGET_HOST_x64 && !__TARGET_HOST_x86 && !__TARGET_HOST_ARMv7" +#endif /* !__TARGET_HOST_x64 && !__TARGET_HOST_x86 && !__TARGET_HOST_ARMv7 */ + +.global _start +_start: + _START + +.global syscall_0_asm +syscall_0_asm: + SYSCALL_0 + +.global syscall_1_asm +syscall_1_asm: + SYSCALL_1 + +.global syscall_2_asm +syscall_2_asm: + SYSCALL_2 + +.global syscall_3_asm +syscall_3_asm: + SYSCALL_3 + +/** + * setjmp (jmp_buf env) + * + * See also: + * longjmp + * + * @return 0 - if returns from direct call, + * nonzero - if returns after longjmp. + */ +.global setjmp +setjmp: + _SETJMP + +/** + * longjmp (jmp_buf env, int val) + * + * Note: + * if val is not 0, then it would be returned from setjmp, + * otherwise - 0 would be returned. + * + * See also: + * setjmp + */ +.global longjmp +longjmp: + _LONGJMP diff --git a/jerry-libc/target/darwin/jerry-libc-target.c b/jerry-libc/target/darwin/jerry-libc-target.c new file mode 100644 index 000000000..6004af159 --- /dev/null +++ b/jerry-libc/target/darwin/jerry-libc-target.c @@ -0,0 +1,386 @@ +/* Copyright 2014-2015 Samsung Electronics Co., Ltd. + * + * 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. + */ + +/** + * Jerry libc platform-specific functions darwin implementation + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "jerry-libc-defs.h" + +LIBC_UNREACHABLE_STUB_FOR (int raise (int sig_no __attr_unused___)) + +/** + * Exit program with ERR_SYSCALL if syscall_ret_val is negative + */ +#define LIBC_EXIT_ON_ERROR(syscall_ret_val) \ + if ((syscall_ret_val) < 0) \ +{ \ + libc_fatal ("Syscall", __FILE__, __func__, __LINE__); \ +} + +static long int syscall_0 (long int syscall_no); +static long int syscall_1 (long int syscall_no, long int arg1); +static long int syscall_2 (long int syscall_no, long int arg1, long int arg2); +static long int syscall_3 (long int syscall_no, long int arg1, long int arg2, long int arg3); + +extern long int syscall_0_asm (long int syscall_no); +extern long int syscall_1_asm (long int syscall_no, long int arg1); +extern long int syscall_2_asm (long int syscall_no, long int arg1, long int arg2); +extern long int syscall_3_asm (long int syscall_no, long int arg1, long int arg2, long int arg3); + +/** + * System call with no argument. + * + * @return syscall's return value + */ +static __attr_noinline___ long int +syscall_0 (long int syscall_no) /**< syscall number */ +{ + long int ret = syscall_0_asm (syscall_no); + + LIBC_EXIT_ON_ERROR (ret); + + return ret; +} /* syscall_0 */ + +/** + * System call with one argument. + * + * @return syscall's return value + */ +static __attr_noinline___ long int +syscall_1 (long int syscall_no, /**< syscall number */ + long int arg1) /**< argument */ +{ + long int ret = syscall_1_asm (syscall_no, arg1); + + LIBC_EXIT_ON_ERROR (ret); + + return ret; +} /* syscall_1 */ + +/** + * System call with two arguments. + * + * @return syscall's return value + */ +static __attr_noinline___ long int +syscall_2 (long int syscall_no, /**< syscall number */ + long int arg1, /**< first argument */ + long int arg2) /**< second argument */ +{ + long int ret = syscall_2_asm (syscall_no, arg1, arg2); + + LIBC_EXIT_ON_ERROR (ret); + + return ret; +} /* syscall_2 */ + +/** + * System call with three arguments. + * + * @return syscall's return value + */ +static __attr_noinline___ long int +syscall_3 (long int syscall_no, /**< syscall number */ + long int arg1, /**< first argument */ + long int arg2, /**< second argument */ + long int arg3) /**< third argument */ +{ + long int ret = syscall_3_asm (syscall_no, arg1, arg2, arg3); + + LIBC_EXIT_ON_ERROR (ret); + + return ret; +} /* syscall_3 */ + +/** Output of character. Writes the character c, cast to an unsigned char, to stdout. */ +int +putchar (int c) +{ + fwrite (&c, 1, sizeof (char), stdout); + + return c; +} /* putchar */ + +/** + * Output specified string + */ +int +puts (const char *s) /**< string to print */ +{ + while (*s) + { + putchar (*s); + + s++; + } + + return 0; +} /* puts */ + +/** + * Exit - cause normal process termination with specified status code + */ +void __attr_noreturn___ __attr_used___ +exit (int status) /**< status code */ +{ + syscall_1 (SYS_close, (long int)stdin); + syscall_1 (SYS_close, (long int)stdout); + syscall_1 (SYS_close, (long int)stderr); + + syscall_1 (SYS_exit, status); + + while (true) + { + /* unreachable */ + } +} /* exit */ + +/** + * Abort current process, producing an abnormal program termination. + * The function raises the SIGABRT signal. + */ +void __attr_noreturn___ __attr_used___ +abort (void) +{ + syscall_1 (SYS_close, (long int)stdin); + syscall_1 (SYS_close, (long int)stdout); + syscall_1 (SYS_close, (long int)stderr); + + syscall_2 (SYS_kill, syscall_0 (SYS_getpid), SIGABRT); + + while (true) + { + /* unreachable */ + } +} /* abort */ + +/** + * fopen + * + * @return FILE pointer - upon successful completion, + * NULL - otherwise + */ +FILE* +fopen (const char *path, /**< file path */ + const char *mode) /**< file open mode */ +{ + bool may_read = false; + bool may_write = false; + bool truncate = false; + bool create_if_not_exist = false; + bool position_at_end = false; + + LIBC_ASSERT (path != NULL && mode != NULL); + LIBC_ASSERT (mode[1] == '+' || mode[1] == '\0'); + + switch (mode[0]) + { + case 'r': + { + may_read = true; + may_write = (mode[1] == '+'); + break; + } + case 'w': + { + may_write = true; + truncate = true; + create_if_not_exist = true; + may_read = (mode[1] == '+'); + break; + } + case 'a': + { + may_write = true; + position_at_end = true; + create_if_not_exist = true; + if (mode[1] == '+') + { + /* Not supported */ + LIBC_UNREACHABLE (); + } + break; + } + default: + { + LIBC_UNREACHABLE (); + } + } + + int flags = 0; + int access = S_IRUSR | S_IWUSR; + if (may_read && !may_write) + { + flags = O_RDONLY; + } + else if (!may_read && may_write) + { + flags = O_WRONLY; + } + else + { + LIBC_ASSERT (may_read && may_write); + + flags = O_RDWR; + } + + if (truncate) + { + flags |= O_TRUNC; + } + + if (create_if_not_exist) + { + flags |= O_CREAT; + } + + if (position_at_end) + { + flags |= O_APPEND; + } + + long int ret = syscall_3 (SYS_open, (long int) path, flags, access); + + return (void*) (uintptr_t) (ret); +} /* fopen */ + +/** + * The rewind () function sets the file position indicator + * for the stream pointed to by STREAM to the beginning of the file. + */ +void +rewind (FILE *stream) /**< stream pointer */ +{ + syscall_3 (SYS_lseek, (long int) stream, 0, SEEK_SET); +} /* rewind */ + +/** + * fclose + * + * @return 0 - upon successful completion, + * non-zero value - otherwise. + */ +int +fclose (FILE *fp) /**< stream pointer */ +{ + syscall_2 (SYS_close, (long int)fp, 0); + + return 0; +} /* fclose */ + +/** + * fseek + */ +int +fseek (FILE * fp, /**< stream pointer */ + long offset, /**< offset */ + int whence) /**< specifies position type + * to add offset to */ +{ + syscall_3 (SYS_lseek, (long int)fp, offset, whence); + + return 0; +} /* fseek */ + +/** + * ftell + */ +long +ftell (FILE * fp) /**< stream pointer */ +{ + long int ret = syscall_3 (SYS_lseek, (long int)fp, 0, SEEK_CUR); + + return ret; +} /* ftell */ + +/** + * fread + * + * @return number of elements read + */ +size_t +fread (void *ptr, /**< address of buffer to read to */ + size_t size, /**< size of elements to read */ + size_t nmemb, /**< number of elements to read */ + FILE *stream) /**< stream pointer */ +{ + long int ret; + size_t bytes_read = 0; + + if (size == 0) + { + return 0; + } + + do + { + ret = syscall_3 (SYS_read, + (long int) stream, + (long int) ((uint8_t*) ptr + bytes_read), + (long int) (size * nmemb - bytes_read)); + + bytes_read += (size_t)ret; + } + while (bytes_read != size * nmemb && ret != 0); + + return bytes_read / size; +} /* fread */ + +/** + * fwrite + * + * @return number of elements written + */ +size_t +fwrite (const void *ptr, /**< data to write */ + size_t size, /**< size of elements to write */ + size_t nmemb, /**< number of elements */ + FILE *stream) /**< stream pointer */ +{ + size_t bytes_written = 0; + + if (size == 0) + { + return 0; + } + + do + { + long int ret = syscall_3 (SYS_write, + (long int) stream, + (long int) ((uint8_t*) ptr + bytes_written), + (long int) (size * nmemb - bytes_written)); + + bytes_written += (size_t)ret; + } + while (bytes_written != size * nmemb); + + return bytes_written / size; +} /* fwrite */ + diff --git a/main-darwin.cpp b/main-darwin.cpp new file mode 100644 index 000000000..a5f741887 --- /dev/null +++ b/main-darwin.cpp @@ -0,0 +1,319 @@ +/* Copyright 2014-2015 Samsung Electronics Co., Ltd. + * + * 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. + */ + +#include +#include +#include + +#include "jerry.h" +#include "jrt/jrt.h" + +/** + * Maximum command line arguments number + */ +#define JERRY_MAX_COMMAND_LINE_ARGS (64) + +/** + * Maximum size of source code buffer + */ +#define JERRY_SOURCE_BUFFER_SIZE (1048576) + +/** + * Standalone Jerry exit codes + */ +#define JERRY_STANDALONE_EXIT_CODE_OK (0) +#define JERRY_STANDALONE_EXIT_CODE_FAIL (1) + +static uint8_t source_buffer[ JERRY_SOURCE_BUFFER_SIZE ]; + +static const jerry_api_char_t * +read_sources (const char *script_file_names[], + int files_count, + size_t *out_source_size_p) +{ + int i; + uint8_t *source_buffer_tail = source_buffer; + + for (i = 0; i < files_count; i++) + { + const char *script_file_name = script_file_names[i]; + + FILE *file = fopen (script_file_name, "r"); + + if (file == NULL) + { + break; + } + + int fseek_status = fseek (file, 0, SEEK_END); + + if (fseek_status != 0) + { + break; + } + + long script_len = ftell (file); + + if (script_len < 0) + { + fclose (file); + break; + } + + rewind (file); + + const size_t current_source_size = (size_t)script_len; + + if (source_buffer_tail + current_source_size >= source_buffer + sizeof (source_buffer)) + { + fclose (file); + break; + } + + size_t bytes_read = fread (source_buffer_tail, 1, current_source_size, file); + if (bytes_read < current_source_size) + { + fclose (file); + break; + } + + fclose (file); + + source_buffer_tail += current_source_size; + } + + if (i < files_count) + { + JERRY_ERROR_MSG ("Failed to read script N%d\n", i + 1); + + return NULL; + } + else + { + const size_t source_size = (size_t) (source_buffer_tail - source_buffer); + + *out_source_size_p = source_size; + + return (const jerry_api_char_t *) source_buffer; + } +} + +/** + * Provide the 'assert' implementation for the engine. + * + * @return true - if only one argument was passed and the argument is a boolean true. + */ +static bool +assert_handler (const jerry_api_object_t *function_obj_p __attr_unused___, /** < function object */ + const jerry_api_value_t *this_p __attr_unused___, /** < this arg */ + jerry_api_value_t *ret_val_p __attr_unused___, /** < return argument */ + const jerry_api_value_t args_p[], /** < function arguments */ + const jerry_api_length_t args_cnt) /** < number of function arguments */ +{ + if (args_cnt == 1 + && args_p[0].type == JERRY_API_DATA_TYPE_BOOLEAN + && args_p[0].v_bool == true) + { + return true; + } + else + { + JERRY_ERROR_MSG ("Script assertion failed\n"); + exit (JERRY_STANDALONE_EXIT_CODE_FAIL); + } +} /* assert_handler */ + +int +main (int argc, + char **argv) +{ + if (argc >= JERRY_MAX_COMMAND_LINE_ARGS) + { + JERRY_ERROR_MSG ("Too many command line arguments. Current maximum is %d (JERRY_MAX_COMMAND_LINE_ARGS)\n", argc); + + return JERRY_STANDALONE_EXIT_CODE_FAIL; + } + + const char *file_names[JERRY_MAX_COMMAND_LINE_ARGS]; + int i; + int files_counter = 0; + + size_t max_data_bss_size, max_stack_size; + jerry_get_memory_limits (&max_data_bss_size, &max_stack_size); + + // FIXME: + // jrt_set_mem_limits (max_data_bss_size, max_stack_size); + + jerry_flag_t flags = JERRY_FLAG_EMPTY; + +#ifdef JERRY_ENABLE_LOG + const char *log_file_name = NULL; +#endif /* JERRY_ENABLE_LOG */ + for (i = 1; i < argc; i++) + { + if (!strcmp ("-v", argv[i])) + { + printf ("Build date: \t%s\n", jerry_build_date); + printf ("Commit hash:\t%s\n", jerry_commit_hash); + printf ("Branch name:\t%s\n", jerry_branch_name); + printf ("\n"); + } + else if (!strcmp ("--mem-stats", argv[i])) + { + flags |= JERRY_FLAG_MEM_STATS; + } + else if (!strcmp ("--mem-stats-per-opcode", argv[i])) + { + flags |= JERRY_FLAG_MEM_STATS_PER_OPCODE; + } + else if (!strcmp ("--mem-stats-separate", argv[i])) + { + flags |= JERRY_FLAG_MEM_STATS_SEPARATE; + } + else if (!strcmp ("--parse-only", argv[i])) + { + flags |= JERRY_FLAG_PARSE_ONLY; + } + else if (!strcmp ("--show-opcodes", argv[i])) + { + flags |= JERRY_FLAG_SHOW_OPCODES; + } + else if (!strcmp ("--log-level", argv[i])) + { + flags |= JERRY_FLAG_ENABLE_LOG; + if (++i < argc && strlen (argv[i]) == 1 && argv[i][0] >='0' && argv[i][0] <= '3') + { +#ifdef JERRY_ENABLE_LOG + jerry_debug_level = argv[i][0] - '0'; +#endif /* JERRY_ENABLE_LOG */ + } + else + { + JERRY_ERROR_MSG ("Error: wrong format or invalid argument\n"); + return JERRY_STANDALONE_EXIT_CODE_FAIL; + } + } + else if (!strcmp ("--log-file", argv[i])) + { + flags |= JERRY_FLAG_ENABLE_LOG; + if (++i < argc) + { +#ifdef JERRY_ENABLE_LOG + log_file_name = argv[i]; +#endif /* JERRY_ENABLE_LOG */ + } + else + { + JERRY_ERROR_MSG ("Error: wrong format of the arguments\n"); + return JERRY_STANDALONE_EXIT_CODE_FAIL; + } + } + else if (!strcmp ("--abort-on-fail", argv[i])) + { + flags |= JERRY_FLAG_ABORT_ON_FAIL; + } + else + { + file_names[files_counter++] = argv[i]; + } + } + + if (files_counter == 0) + { + return JERRY_STANDALONE_EXIT_CODE_OK; + } + else + { + size_t source_size; + const jerry_api_char_t *source_p = read_sources (file_names, files_counter, &source_size); + + if (source_p == NULL) + { + return JERRY_STANDALONE_EXIT_CODE_FAIL; + } + else + { +#ifdef JERRY_ENABLE_LOG + if (log_file_name) + { + jerry_log_file = fopen (log_file_name, "w"); + if (jerry_log_file == NULL) + { + JERRY_ERROR_MSG ("Failed to open log file: %s\n", log_file_name); + return JERRY_STANDALONE_EXIT_CODE_FAIL; + } + } + else + { + jerry_log_file = stdout; + } +#endif /* JERRY_ENABLE_LOG */ + + jerry_init (flags); + + jerry_api_object_t *global_obj_p = jerry_api_get_global (); + jerry_api_object_t *assert_func_p = jerry_api_create_external_function (assert_handler); + jerry_api_value_t assert_value; + assert_value.type = JERRY_API_DATA_TYPE_OBJECT; + assert_value.v_object = assert_func_p; + + bool is_assert_added = jerry_api_set_object_field_value (global_obj_p, + (jerry_api_char_t *) "assert", + &assert_value); + + jerry_api_release_value (&assert_value); + jerry_api_release_object (global_obj_p); + + if (!is_assert_added) + { + JERRY_ERROR_MSG ("Failed to register 'assert' method."); + } + + jerry_completion_code_t ret_code = JERRY_COMPLETION_CODE_OK; + + if (!jerry_parse (source_p, source_size)) + { + /* unhandled SyntaxError */ + ret_code = JERRY_COMPLETION_CODE_UNHANDLED_EXCEPTION; + } + else + { + if ((flags & JERRY_FLAG_PARSE_ONLY) == 0) + { + ret_code = jerry_run (); + } + } + + jerry_cleanup (); + +#ifdef JERRY_ENABLE_LOG + if (jerry_log_file && jerry_log_file != stdout) + { + fclose (jerry_log_file); + jerry_log_file = NULL; + } +#endif /* JERRY_ENABLE_LOG */ + + if (ret_code == JERRY_COMPLETION_CODE_OK) + { + return JERRY_STANDALONE_EXIT_CODE_OK; + } + else + { + return JERRY_STANDALONE_EXIT_CODE_FAIL; + } + } + } +}