# # Copyright 2016 WebAssembly Community Group participants # # 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. # cmake_minimum_required(VERSION 2.6) project(WABT) option(BUILD_TESTS "Build GTest-based tests" ON) option(BUILD_TOOLS "Build wabt commandline tools" ON) option(RUN_RE2C "Run re2c" ON) option(USE_ASAN "Use address sanitizer" OFF) option(USE_MSAN "Use memory sanitizer" OFF) option(USE_LSAN "Use leak sanitizer" OFF) option(USE_UBSAN "Use undefined behavior sanitizer" OFF) option(CODE_COVERAGE "Build with code coverage enabled" OFF) option(WITH_EXCEPTIONS "Build with exceptions enabled" OFF) if (${CMAKE_C_COMPILER_ID} STREQUAL "Clang") set(COMPILER_IS_CLANG 1) set(COMPILER_IS_GNU 0) set(COMPILER_IS_MSVC 0) elseif (${CMAKE_C_COMPILER_ID} STREQUAL "GNU") set(COMPILER_IS_CLANG 0) set(COMPILER_IS_GNU 1) set(COMPILER_IS_MSVC 0) elseif (${CMAKE_C_COMPILER_ID} STREQUAL "MSVC") set(COMPILER_IS_CLANG 0) set(COMPILER_IS_GNU 0) set(COMPILER_IS_MSVC 1) elseif (${CMAKE_SYSTEM_NAME} STREQUAL "Emscripten") set(COMPILER_IS_CLANG 1) set(COMPILER_IS_GNU 0) set(COMPILER_IS_MSVC 0) else () set(COMPILER_IS_CLANG 0) set(COMPILER_IS_GNU 0) set(COMPILER_IS_MSVC 0) endif () include(CheckIncludeFile) include(CheckSymbolExists) check_include_file("alloca.h" HAVE_ALLOCA_H) check_include_file("unistd.h" HAVE_UNISTD_H) check_symbol_exists(snprintf "stdio.h" HAVE_SNPRINTF) check_symbol_exists(sysconf "unistd.h" HAVE_SYSCONF) check_symbol_exists(strcasecmp "strings.h" HAVE_STRCASECMP) if (WIN32) check_symbol_exists(ENABLE_VIRTUAL_TERMINAL_PROCESSING "windows.h" HAVE_WIN32_VT100) endif () include(CheckTypeSize) check_type_size(ssize_t SSIZE_T) check_type_size(size_t SIZEOF_SIZE_T) configure_file( ${WABT_SOURCE_DIR}/src/config.h.in ${WABT_BINARY_DIR}/config.h ) include_directories(${WABT_SOURCE_DIR} ${WABT_BINARY_DIR}) if (COMPILER_IS_MSVC) # disable warning C4018: signed/unsigned mismatch # disable warning C4056, C4756: overflow in floating-point constant arithmetic # seems to not like float compare w/ HUGE_VALF; bug? # disable warnings C4267 and C4244: conversion/truncation from larger to smaller type. # disable warning C4800: implicit conversion from larger int to bool add_definitions(-W3 -wd4018 -wd4056 -wd4756 -wd4267 -wd4244 -wd4800 -WX -D_CRT_SECURE_NO_WARNINGS -D_SCL_SECURE_NO_WARNINGS) if (NOT WITH_EXCEPTIONS) # disable exception use in C++ library add_definitions(-D_HAS_EXCEPTIONS=0) endif () else () # disable -Wunused-parameter: this is really common when implementing # interfaces, etc. # disable -Wpointer-arith: this is a GCC extension, and doesn't work in MSVC. add_definitions( -Wall -Wextra -Werror -Wno-unused-parameter -Wpointer-arith -g -std=c++11 -Wold-style-cast -Wuninitialized ) if (NOT WITH_EXCEPTIONS) add_definitions(-fno-exceptions) endif () # Need to define __STDC_*_MACROS because C99 specifies that C++ shouldn't # define format (e.g. PRIu64) or limit (e.g. UINT32_MAX) macros without the # definition, and some libcs (e.g. glibc2.17 and earlier) follow that. add_definitions(-D__STDC_LIMIT_MACROS=1 -D__STDC_FORMAT_MACROS=1) if (MINGW) # _POSIX is needed to ensure we use mingw printf # instead of the VC runtime one. add_definitions(-D_POSIX) endif () if (COMPILER_IS_GNU) # disable -Wclobbered: it seems to be guessing incorrectly about a local # variable being clobbered by longjmp. add_definitions(-Wno-clobbered) endif () if (NOT EMSCRIPTEN) # try to get the target architecture by compiling a dummy.c file and # checking the architecture using the file command. file(WRITE ${WABT_BINARY_DIR}/dummy.c "main(){}") try_compile( COMPILE_OK ${WABT_BINARY_DIR} ${WABT_BINARY_DIR}/dummy.c COPY_FILE ${WABT_BINARY_DIR}/dummy ) if (COMPILE_OK) execute_process( COMMAND file ${WABT_BINARY_DIR}/dummy RESULT_VARIABLE FILE_RESULT OUTPUT_VARIABLE FILE_OUTPUT ERROR_QUIET ) if (FILE_RESULT EQUAL 0) if (${FILE_OUTPUT} MATCHES "x86[-_]64") set(TARGET_ARCH "x86-64") elseif (${FILE_OUTPUT} MATCHES "Intel 80386") set(TARGET_ARCH "i386") elseif (${FILE_OUTPUT} MATCHES "ARM") set(TARGET_ARCH "ARM") else () message(WARNING "Unknown target architecture!") endif () else () message(WARNING "Error running file on dummy executable") endif () else () message(WARNING "Error compiling dummy.c file") endif () if (TARGET_ARCH STREQUAL "i386") # wasm doesn't allow for x87 floating point math add_definitions(-msse2 -mfpmath=sse) endif () endif () endif () set(USE_SANITIZER FALSE) function(SANITIZER NAME FLAGS) if (${NAME}) if (USE_SANITIZER) message(FATAL_ERROR "Only one sanitizer allowed") endif () set(USE_SANITIZER TRUE PARENT_SCOPE) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${FLAGS}" PARENT_SCOPE) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${FLAGS}" PARENT_SCOPE) endif () endfunction() SANITIZER(USE_ASAN "-fsanitize=address") SANITIZER(USE_MSAN "-fsanitize=memory") SANITIZER(USE_LSAN "-fsanitize=leak") if (USE_UBSAN) # -fno-sanitize-recover was deprecated, see if we are compiling with a newer # clang that requires -fno-sanitize-recover=all. set(UBSAN_BLACKLIST ${WABT_SOURCE_DIR}/ubsan.blacklist) include(CheckCXXCompilerFlag) CHECK_CXX_COMPILER_FLAG("-fsanitize=undefined -fno-sanitize-recover -Wall -Werror" HAS_UBSAN_RECOVER_BARE) if (HAS_UBSAN_RECOVER_BARE) SANITIZER(USE_UBSAN "-fsanitize=undefined -fno-sanitize-recover -fsanitize-blacklist=${UBSAN_BLACKLIST}") endif () CHECK_CXX_COMPILER_FLAG("-fsanitize=undefined -fno-sanitize-recover=all -Wall -Werror" HAS_UBSAN_RECOVER_ALL) if (HAS_UBSAN_RECOVER_ALL) SANITIZER(USE_UBSAN "-fsanitize=undefined -fno-sanitize-recover=all -fsanitize-blacklist=${UBSAN_BLACKLIST}") endif () if (NOT USE_SANITIZER) message(FATAL_ERROR "UBSAN is not supported") endif () endif () set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${WABT_SOURCE_DIR}/cmake) find_package(RE2C) if (RUN_RE2C AND RE2C_EXECUTABLE AND (NOT ${RE2C_VERSION} VERSION_LESS "0.16")) message(STATUS "Using generated re2c lexer") set(WAST_LEXER_CC ${WABT_SOURCE_DIR}/src/wast-lexer.cc) set(WAST_LEXER_GEN_CC ${WABT_BINARY_DIR}/wast-lexer-gen.cc) RE2C_TARGET( NAME WAST_LEXER_GEN_CC INPUT ${WAST_LEXER_CC} OUTPUT ${WAST_LEXER_GEN_CC} OPTIONS -bc8 -W -Werror ) else () message(STATUS "Using prebuilt re2c lexer") set(WAST_LEXER_GEN_CC src/prebuilt/wast-lexer-gen.cc) endif () add_custom_target(everything) add_library(libwabt STATIC src/token.cc src/opcode.cc src/error-handler.cc src/hash-util.cc src/filenames.cc src/string-view.cc src/ir.cc src/expr-visitor.cc src/lexer-source.cc src/lexer-source-line-finder.cc src/wast-parser-lexer-shared.cc ${WAST_LEXER_GEN_CC} src/wast-parser.cc src/type-checker.cc src/validator.cc src/binary-reader.cc src/binary-reader-logging.cc src/binary-writer.cc src/binary-writer-spec.cc src/binary-reader-ir.cc src/binding-hash.cc src/wat-writer.cc src/interp.cc src/binary-reader-interp.cc src/apply-names.cc src/generate-names.cc src/resolve-names.cc src/binary.cc src/color.cc src/common.cc src/config.cc src/feature.cc src/leb128.cc src/literal.cc src/option-parser.cc src/stream.cc src/tracing.cc src/utf8.cc ) set_target_properties(libwabt PROPERTIES OUTPUT_NAME wabt) if (NOT EMSCRIPTEN) if (CODE_COVERAGE) add_definitions("-fprofile-arcs -ftest-coverage") if (COMPILER_IS_CLANG) set(CMAKE_EXE_LINKER_FLAGS "--coverage") else () link_libraries(gcov) endif () endif () function(wabt_executable name) # ARGV contains all arguments; remove the first one, ${name}, so it's just # a list of sources. list(REMOVE_AT ARGV 0) add_executable(${name} ${ARGV}) add_dependencies(everything ${name}) target_link_libraries(${name} libwabt) set_property(TARGET ${name} PROPERTY CXX_STANDARD 11) set_property(TARGET ${name} PROPERTY CXX_STANDARD_REQUIRED ON) list(APPEND WABT_EXECUTABLES ${name}) set(WABT_EXECUTABLES ${WABT_EXECUTABLES} PARENT_SCOPE) add_custom_target(${name}-copy-to-bin ALL COMMAND ${CMAKE_COMMAND} -E make_directory ${WABT_SOURCE_DIR}/bin COMMAND ${CMAKE_COMMAND} -E copy $ ${WABT_SOURCE_DIR}/bin DEPENDS ${name} ) endfunction() if (BUILD_TOOLS) # wat2wasm wabt_executable(wat2wasm src/tools/wat2wasm.cc) # wast2json wabt_executable(wast2json src/tools/wast2json.cc) # wasm2wat wabt_executable(wasm2wat src/tools/wasm2wat.cc) # wasm2c wabt_executable(wasm2c src/tools/wasm2c.cc src/c-writer.cc) # wasm-opcodecnt wabt_executable(wasm-opcodecnt src/tools/wasm-opcodecnt.cc src/binary-reader-opcnt.cc) # wasm-objdump wabt_executable(wasm-objdump src/tools/wasm-objdump.cc src/binary-reader-objdump.cc) # wasm-interp wabt_executable(wasm-interp src/tools/wasm-interp.cc) if (COMPILER_IS_CLANG OR COMPILER_IS_GNU) target_link_libraries(wasm-interp m) endif () # spectest-interp wabt_executable(spectest-interp src/tools/spectest-interp.cc) if (COMPILER_IS_CLANG OR COMPILER_IS_GNU) target_link_libraries(spectest-interp m) endif () # wat-desugar wabt_executable(wat-desugar src/tools/wat-desugar.cc) # wasm-validate wabt_executable(wasm-validate src/tools/wasm-validate.cc) endif () find_package(Threads) if (BUILD_TESTS) if (NOT EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/third_party/gtest/googletest) message(FATAL_ERROR "Can't find third_party/gtest. Run git submodule update --init, or disable with CMake -DBUILD_TESTS=OFF.") endif () include_directories( third_party/gtest/googletest third_party/gtest/googletest/include ) # gtest add_library(libgtest STATIC third_party/gtest/googletest/src/gtest-all.cc ) # hexfloat-test set(HEXFLOAT_TEST_SRCS src/literal.cc src/test-hexfloat.cc third_party/gtest/googletest/src/gtest_main.cc ) add_executable(hexfloat_test ${HEXFLOAT_TEST_SRCS}) add_dependencies(everything hexfloat_test) target_link_libraries(hexfloat_test libgtest ${CMAKE_THREAD_LIBS_INIT}) set_property(TARGET hexfloat_test PROPERTY CXX_STANDARD 11) set_property(TARGET hexfloat_test PROPERTY CXX_STANDARD_REQUIRED ON) # wabt-unittests set(UNITTESTS_SRCS src/test-circular-array.cc src/test-interp.cc src/test-intrusive-list.cc src/test-literal.cc src/test-string-view.cc src/test-filenames.cc src/test-utf8.cc src/test-wast-parser.cc third_party/gtest/googletest/src/gtest_main.cc ) wabt_executable(wabt-unittests ${UNITTESTS_SRCS}) target_link_libraries(wabt-unittests libgtest ${CMAKE_THREAD_LIBS_INIT}) endif () if (NOT CMAKE_VERSION VERSION_LESS "3.2") set(USES_TERMINAL USES_TERMINAL) endif () # test running find_package(PythonInterp 2.7 REQUIRED) set(RUN_TESTS_PY ${WABT_SOURCE_DIR}/test/run-tests.py) add_custom_target(run-tests COMMAND ${PYTHON_EXECUTABLE} ${RUN_TESTS_PY} --bindir ${CMAKE_BINARY_DIR} DEPENDS ${WABT_EXECUTABLES} WORKING_DIRECTORY ${WABT_SOURCE_DIR} ${USES_TERMINAL} ) # install if (BUILD_TOOLS OR BUILD_TESTS) install(TARGETS ${WABT_EXECUTABLES} DESTINATION bin) endif () else () # emscripten stuff # just dump everything into one binary so we can reference it from JavaScript add_definitions(-Wno-warn-absolute-paths) add_executable(libwabtjs src/emscripten-helpers.cc) add_dependencies(everything libwabtjs) target_link_libraries(libwabtjs libwabt) set_target_properties(libwabtjs PROPERTIES OUTPUT_NAME libwabt) set(WABT_POST_JS ${WABT_SOURCE_DIR}/src/wabt.post.js) set(EMSCRIPTEN_EXPORTED_JSON ${WABT_SOURCE_DIR}/src/emscripten-exported.json) set(LIBWABT_LINK_FLAGS --memory-init-file 0 --post-js ${WABT_POST_JS} -s EXPORTED_FUNCTIONS=\"@${EMSCRIPTEN_EXPORTED_JSON}\" -s RESERVED_FUNCTION_POINTERS=10 -s NO_EXIT_RUNTIME=1 -s ALLOW_MEMORY_GROWTH=1 -s MODULARIZE=1 -s EXPORT_NAME=\"'WabtModule'\" -s WASM=0 -Oz --llvm-lto 1 ) string(REPLACE ";" " " LIBWABT_LINK_FLAGS_STR "${LIBWABT_LINK_FLAGS}") set_target_properties(libwabtjs PROPERTIES LINK_FLAGS "${LIBWABT_LINK_FLAGS_STR}" LINK_DEPENDS "${WABT_POST_JS};${EMSCRIPTEN_EXPORTED_JSON}" ) endif ()