From 9de7165f9157812a827f96a73c70dea1d909b763 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Tue, 3 Sep 2013 15:14:06 +0300 Subject: [PATCH] Improve CMake toolchain file to use response files. Avoid the compiler detection mechanism that could throw CMake off depending on what is in Windows PATH. Use CMAKE_EXECUTABLE_SUFFIX to specify whether to build .html or .js. --- cmake/Platform/Emscripten.cmake | 88 +++++++++++++++++++++++--- tests/cmake/target_html/CMakeLists.txt | 8 ++- tests/cmake/target_js/CMakeLists.txt | 18 +++++- tests/test_other.py | 12 ++-- 4 files changed, 107 insertions(+), 19 deletions(-) diff --git a/cmake/Platform/Emscripten.cmake b/cmake/Platform/Emscripten.cmake index aafd38a83..a8667cd95 100644 --- a/cmake/Platform/Emscripten.cmake +++ b/cmake/Platform/Emscripten.cmake @@ -16,33 +16,105 @@ set(CMAKE_SYSTEM_NAME Emscripten) set(CMAKE_SYSTEM_VERSION 1) +set(CMAKE_CROSSCOMPILING TRUE) + +# Do a no-op access on the CMAKE_TOOLCHAIN_FILE variable so that CMake will not issue a warning on it being unused. +if (CMAKE_TOOLCHAIN_FILE) +endif() + +# Locate where the Emscripten compiler resides in relative to this toolchain file. if ("${EMSCRIPTEN_ROOT_PATH}" STREQUAL "") - set(CMAKE_FIND_ROOT_PATH "$ENV{EMSCRIPTEN}") + get_filename_component(GUESS_EMSCRIPTEN_ROOT_PATH "${CMAKE_CURRENT_LIST_DIR}/../../" ABSOLUTE) + if (EXISTS "${GUESS_EMSCRIPTEN_ROOT_PATH}/emranlib") + set(EMSCRIPTEN_ROOT_PATH "${GUESS_EMSCRIPTEN_ROOT_PATH}") + message(STATUS "Guessed ${EMSCRIPTEN_ROOT_PATH}") + endif() +endif() + +# If not found by above search, locate using the EMSCRIPTEN environment variable. +if ("${EMSCRIPTEN_ROOT_PATH}" STREQUAL "") + set(EMSCRIPTEN_ROOT_PATH "$ENV{EMSCRIPTEN}") +endif() + +# Abort if not found. +if ("${EMSCRIPTEN_ROOT_PATH}" STREQUAL "") + message(FATAL_ERROR "Could not locate the Emscripten compiler toolchain directory! Either set the EMSCRIPTEN environment variable, or pass -DEMSCRIPTEN_ROOT_PATH=xxx to CMake to explicitly specify the location of the compiler!") +endif() + +# Normalize, convert Windows backslashes to forward slashes or CMake will crash. +get_filename_component(EMSCRIPTEN_ROOT_PATH "${EMSCRIPTEN_ROOT_PATH}" ABSOLUTE) + +set(CMAKE_FIND_ROOT_PATH "${EMSCRIPTEN_ROOT_PATH}") + +if (CMAKE_HOST_WIN32) + set(EMCC_SUFFIX ".bat") else() - set(CMAKE_FIND_ROOT_PATH "${EMSCRIPTEN_ROOT_PATH}") + set(EMCC_SUFFIX "") endif() # Specify the compilers to use for C and C++ if ("${CMAKE_C_COMPILER}" STREQUAL "") - set(CMAKE_C_COMPILER "emcc.bat") - set(CMAKE_CXX_COMPILER "em++.bat") - set(CMAKE_AR "emar.bat") - set(CMAKE_RANLIB "emranlib.bat") + set(CMAKE_C_COMPILER "${EMSCRIPTEN_ROOT_PATH}/emcc${EMCC_SUFFIX}") endif() +if ("${CMAKE_CXX_COMPILER}" STREQUAL "") + set(CMAKE_CXX_COMPILER "${EMSCRIPTEN_ROOT_PATH}/em++${EMCC_SUFFIX}") +endif() + +if ("${CMAKE_AR}" STREQUAL "") + set(CMAKE_AR "${EMSCRIPTEN_ROOT_PATH}/emar${EMCC_SUFFIX}") +endif() + +if ("${CMAKE_RANLIB}" STREQUAL "") + set(CMAKE_RANLIB "${EMSCRIPTEN_ROOT_PATH}/emranlib${EMCC_SUFFIX}") +endif() + +# Don't do compiler autodetection, since we are cross-compiling. +include(CMakeForceCompiler) +CMAKE_FORCE_C_COMPILER("${CMAKE_C_COMPILER}" Clang) +CMAKE_FORCE_CXX_COMPILER("${CMAKE_CXX_COMPILER}" Clang) set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE BOTH) set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) +SET(CMAKE_LINK_LIBRARY_SUFFIX "") +SET(CMAKE_STATIC_LIBRARY_PREFIX "") +SET(CMAKE_STATIC_LIBRARY_SUFFIX ".bc") +SET(CMAKE_SHARED_LIBRARY_PREFIX "") +SET(CMAKE_SHARED_LIBRARY_SUFFIX ".bc") +IF (NOT CMAKE_EXECUTABLE_SUFFIX) + SET(CMAKE_EXECUTABLE_SUFFIX ".js") +endif() +SET(CMAKE_DL_LIBS "" ) + +SET(CMAKE_FIND_LIBRARY_PREFIXES "") +SET(CMAKE_FIND_LIBRARY_SUFFIXES ".bc") + +SET(CMAKE_C_USE_RESPONSE_FILE_FOR_OBJECTS 1) +SET(CMAKE_CXX_USE_RESPONSE_FILE_FOR_OBJECTS 1) +SET(CMAKE_C_USE_RESPONSE_FILE_FOR_INCLUDES 1) +SET(CMAKE_CXX_USE_RESPONSE_FILE_FOR_INCLUDES 1) + +set(CMAKE_C_RESPONSE_FILE_LINK_FLAG "@") +set(CMAKE_CXX_RESPONSE_FILE_LINK_FLAG "@") + # Specify the program to use when building static libraries. Force Emscripten-related command line options to clang. -set(CMAKE_CXX_ARCHIVE_CREATE "${CMAKE_CXX_COMPILER} -o -emit-llvm ") -set(CMAKE_C_ARCHIVE_CREATE "${CMAKE_C_COMPILER} -o -emit-llvm ") +set(CMAKE_CXX_ARCHIVE_CREATE "${CMAKE_CXX_COMPILER} ${CMAKE_START_TEMP_FILE} -o -emit-llvm ${CMAKE_END_TEMP_FILE}") +set(CMAKE_C_ARCHIVE_CREATE "${CMAKE_C_COMPILER} ${CMAKE_START_TEMP_FILE} -o -emit-llvm ${CMAKE_END_TEMP_FILE}") # Set a global EMSCRIPTEN variable that can be used in client CMakeLists.txt to detect when building using Emscripten. # There seems to be some kind of bug with CMake, so you might need to define this manually on the command line with "-DEMSCRIPTEN=1". set(EMSCRIPTEN 1) +# We are cross-compiling, so unset the common CMake variables that represent the target platform. Leave UNIX define enabled, since Emscripten +# mimics a Linux environment. +SET(WIN32) +SET(APPLE) + +set(CMAKE_C_SIZEOF_DATA_PTR 4) +set(CMAKE_CXX_SIZEOF_DATA_PTR 4) + set(CMAKE_C_FLAGS_RELEASE "-DNDEBUG" CACHE STRING "Emscripten-overridden CMAKE_C_FLAGS_RELEASE") set(CMAKE_C_FLAGS_MINSIZEREL "-DNDEBUG" CACHE STRING "Emscripten-overridden CMAKE_C_FLAGS_MINSIZEREL") set(CMAKE_C_FLAGS_RELWITHDEBINFO "" CACHE STRING "Emscripten-overridden CMAKE_C_FLAGS_RELWITHDEBINFO") diff --git a/tests/cmake/target_html/CMakeLists.txt b/tests/cmake/target_html/CMakeLists.txt index 9f891e718..8b0528eb4 100644 --- a/tests/cmake/target_html/CMakeLists.txt +++ b/tests/cmake/target_html/CMakeLists.txt @@ -1,6 +1,6 @@ cmake_minimum_required(VERSION 2.8) -project(hello_world_gles.html) +project(hello_world_gles) file(GLOB sourceFiles ../../hello_world_gles.c) @@ -10,5 +10,7 @@ else() # Either MinSizeRel, RelWithDebInfo or Release, all which run with optimi SET(linkFlags "-O2") endif() -add_executable(hello_world_gles.html ${sourceFiles}) -set_target_properties(hello_world_gles.html PROPERTIES LINK_FLAGS "${linkFlags}") +SET(CMAKE_EXECUTABLE_SUFFIX ".html") + +add_executable(hello_world_gles ${sourceFiles}) +set_target_properties(hello_world_gles PROPERTIES LINK_FLAGS "${linkFlags}") diff --git a/tests/cmake/target_js/CMakeLists.txt b/tests/cmake/target_js/CMakeLists.txt index 860b70a9f..a1228c735 100644 --- a/tests/cmake/target_js/CMakeLists.txt +++ b/tests/cmake/target_js/CMakeLists.txt @@ -1,6 +1,6 @@ cmake_minimum_required(VERSION 2.8) -project(hello_world.js) +project(hello_world) file(GLOB sourceFiles ../../hello_world.cpp) @@ -10,5 +10,17 @@ else() # Either MinSizeRel, RelWithDebInfo or Release, all which run with optimi SET(linkFlags "-O2") endif() -add_executable(hello_world.js ${sourceFiles}) -set_target_properties(hello_world.js PROPERTIES LINK_FLAGS "${linkFlags}") +if (WIN32) + message(FATAL_ERROR "WIN32 should not be defined when cross-compiling!") +endif() + +if (APPLE) + message(FATAL_ERROR "APPLE should not be defined when cross-compiling!") +endif() + +if (NOT CMAKE_C_SIZEOF_DATA_PTR) + message(FATAL_ERROR "CMAKE_C_SIZEOF_DATA_PTR was not defined!") +endif() + +add_executable(hello_world ${sourceFiles}) +set_target_properties(hello_world PROPERTIES LINK_FLAGS "${linkFlags}") diff --git a/tests/test_other.py b/tests/test_other.py index c6f5c333a..1723db911 100644 --- a/tests/test_other.py +++ b/tests/test_other.py @@ -281,9 +281,11 @@ f.close() if os.name == 'nt': make_command = 'mingw32-make' + generator = 'MinGW Makefiles' emscriptencmaketoolchain = path_from_root('cmake', 'Platform', 'Emscripten.cmake') else: make_command = 'make' + generator = 'Unix Makefiles' emscriptencmaketoolchain = path_from_root('cmake', 'Platform', 'Emscripten_unix.cmake') cmake_cases = ['target_js', 'target_html'] @@ -301,11 +303,11 @@ f.close() cmd = ['cmake', '-DCMAKE_TOOLCHAIN_FILE='+emscriptencmaketoolchain, '-DCMAKE_BUILD_TYPE=' + configuration, '-DCMAKE_MODULE_PATH=' + path_from_root('cmake').replace('\\', '/'), - '-G' 'Unix Makefiles', cmakelistsdir] + '-G', generator, cmakelistsdir] ret = Popen(cmd, stdout=PIPE, stderr=PIPE).communicate() - if ret[1] != None and len(ret[1].strip()) > 0: + if len(ret) > 1 and ret[1] != None and len(ret[1].strip()) > 0: print >> sys.stderr, ret[1] # If there were any errors, print them directly to console for diagnostics. - if 'error' in ret[1].lower(): + if len(ret) > 1 and ret[1] != None and 'error' in ret[1].lower(): print >> sys.stderr, 'Failed command: ' + ' '.join(cmd) print >> sys.stderr, 'Result:\n' + ret[1] raise Exception('cmake call failed!') @@ -314,9 +316,9 @@ f.close() # Build cmd = [make_command] ret = Popen(cmd, stdout=PIPE).communicate() - if ret[1] != None and len(ret[1].strip()) > 0: + if len(ret) > 1 and ret[1] != None and len(ret[1].strip()) > 0: print >> sys.stderr, ret[1] # If there were any errors, print them directly to console for diagnostics. - if 'error' in ret[0].lower() and not '0 error(s)' in ret[0].lower(): + if len(ret) > 0 and ret[0] != None and 'error' in ret[0].lower() and not '0 error(s)' in ret[0].lower(): print >> sys.stderr, 'Failed command: ' + ' '.join(cmd) print >> sys.stderr, 'Result:\n' + ret[0] raise Exception('make failed!')