Browse Source

Initial attempt to support MODULE library type for Web platform.
Disallow memory growth when using MODULE lib-type.
Move the resource defining and checking logic into their own macros.

Yao Wei Tjong 姚伟忠 8 years ago
parent
commit
9d84ccffe4

+ 8 - 5
.travis.yml

@@ -399,6 +399,7 @@ env:
   global:
     - secure: SLJCjkjDsTMbCIV9Wecz5JATnhk0fuzlnLMeZdvvFDv+8NL8cXyutkU0VfyRSLf3HSD1Js79a6fRMROyVGWj/w/BRrjqGnZzsB6+ZeJNnadiVIF5Gh+w90We5ccvSp2G4DyYgwkNnkKlJK7zNEWGu/K+bHL1EOCA+EIVrFMyA44=
     - secure: ecj/PwpbHkH9AYFsc2TMeRuNm5E3xMM8A0x4AcGhzpwDuZWdFx3R1T4G9u45Z5aUyTJWGqOeX1JPaEVVFZuYnNBKRy0kmiUrM9EE0j7WsT57K48tP1ysn2ynyvHgbYkKOfYR0t8XAMWTBbulT9DVVk3DS69//2WgiXGDVUEJTyI=
+    - numjobs=1
     - WEB=1
     - EMSCRIPTEN_SHARE_DATA=1
     - EMSCRIPTEN_SHARE_JS=1
@@ -408,10 +409,12 @@ env:
     - CCACHE_COMPRESS=1
     - CCACHE_MAXSIZE=100M
   matrix:
-    - URHO3D_LIB_TYPE=STATIC numjobs=1
-    - URHO3D_LIB_TYPE=SHARED numjobs=2
-    - URHO3D_LIB_TYPE=STATIC EMSCRIPTEN_WASM=1 numjobs=1
-    - URHO3D_LIB_TYPE=SHARED EMSCRIPTEN_WASM=1 numjobs=2
+    - URHO3D_LIB_TYPE=MODULE numjobs=4
+    - URHO3D_LIB_TYPE=STATIC
+    - URHO3D_LIB_TYPE=SHARED
+    # URHO3D_LIB_TYPE=MODULE EMSCRIPTEN_WASM=1 numjobs=4
+    - URHO3D_LIB_TYPE=STATIC EMSCRIPTEN_WASM=1
+    - URHO3D_LIB_TYPE=SHARED EMSCRIPTEN_WASM=1
 matrix:
   fast_finish: true
 before_script:
@@ -424,7 +427,7 @@ before_script:
   - git clone --depth 1 --branch $EMSCRIPTEN_BRANCH https://github.com/urho3d/emscripten-sdk.git && emscripten-sdk/emsdk activate --build=Release sdk-${EMSCRIPTEN_BRANCH}-64bit $BINARYEN && source emscripten-sdk/emsdk_env.sh
   - export PATH=$(whereis -b ccache |grep -o '\S*lib\S*'):$PATH; for f in $EMSCRIPTEN/{emcc,em++}; do touch -d "2015-09-01 00:00:00 +0800" $f; done
   - rake ci_setup_cache
-script: rake ci && if [[ "$TRAVIS_BRANCH" == "Web-CI" ]] && [[ ! $EMSCRIPTEN_WASM ]] && [[ "$TRAVIS_PULL_REQUEST" == "false" ]] && [[ "$URHO3D_LIB_TYPE" == "SHARED" ]]; then rake ci_emscripten_samples_update; fi && if [ $PACKAGE_UPLOAD ]; then rake ci_package_upload; fi && rake ci_timer
+script: rake ci && if [[ "$TRAVIS_BRANCH" == "Web-CI" ]] && [[ ! $EMSCRIPTEN_WASM ]] && [[ "$TRAVIS_PULL_REQUEST" == "false" ]] && [[ "$URHO3D_LIB_TYPE" == "MODULE" ]]; then rake ci_emscripten_samples_update; fi && if [ $PACKAGE_UPLOAD ]; then rake ci_package_upload; fi && rake ci_timer
 after_script: rake ci_teardown_cache
 
 ---

+ 2 - 2
CMake/Modules/CheckHost.cmake

@@ -81,8 +81,8 @@ else ()
     endif ()
     # Temporary workaround - test if PCH could be enabled when using Clang compiler toolchain
     if (CMAKE_CXX_COMPILER_ID MATCHES Clang)
-        # Turn off PCH when building on macOS host with ccache 3.3.1+ (the last known bad version) and when targeting Android platform
-        if ((APPLE AND NOT CCACHE_VERSION VERSION_LESS 3.3.1) OR ANDROID)
+        # Turn off PCH when building on macOS host with ccache 3.3.1+ (the last known bad version) and when targeting Android and Web platforms
+        if ((APPLE AND NOT CCACHE_VERSION VERSION_LESS 3.3.1) OR ANDROID OR WEB)
             set (URHO3D_PCH FALSE CACHE INTERNAL "" FORCE)
         endif ()
     endif ()

+ 31 - 19
CMake/Modules/FindUrho3D.cmake

@@ -99,6 +99,10 @@ else ()
         if (NOT CMAKE_FIND_LIBRARY_SUFFIXES MATCHES ^\\.\(a|lib\))
             list (REVERSE CMAKE_FIND_LIBRARY_SUFFIXES)
         endif ()
+        # Cater for the shared library extension in Emscripten build which is ".bc" instead of ".so", and also cater for the module library extension
+        if (EMSCRIPTEN)
+            string (REPLACE .so .bc CMAKE_FIND_LIBRARY_SUFFIXES "${CMAKE_FIND_LIBRARY_SUFFIXES};.js")   # Stringify for string replacement
+        endif ()
         # If library type is specified then only search for the requested library type
         if (NOT MSVC AND URHO3D_LIB_TYPE)      # MSVC static lib and import lib have a same extension, so cannot use it for searches
             if (URHO3D_LIB_TYPE STREQUAL STATIC)
@@ -108,17 +112,17 @@ else ()
                     set (CMAKE_FIND_LIBRARY_SUFFIXES .dll.a)
                 elseif (APPLE)
                     set (CMAKE_FIND_LIBRARY_SUFFIXES .dylib)
+                elseif (EMSCRIPTEN)
+                    set (CMAKE_FIND_LIBRARY_SUFFIXES .bc)
                 else ()
                     set (CMAKE_FIND_LIBRARY_SUFFIXES .so)
                 endif ()
+            elseif (URHO3D_LIB_TYPE STREQUAL MODULE AND EMSCRIPTEN)
+                set (CMAKE_FIND_LIBRARY_SUFFIXES .js)
             else ()
                 message (FATAL_ERROR "Library type: '${URHO3D_LIB_TYPE}' is not supported")
             endif ()
         endif ()
-        # Cater for the shared library extension in Emscripten build which is ".bc" instead of ".so"
-        if (EMSCRIPTEN)
-            string (REPLACE .so .bc CMAKE_FIND_LIBRARY_SUFFIXES "${CMAKE_FIND_LIBRARY_SUFFIXES}")   # Stringify for string replacement
-        endif ()
         # The PATH_SUFFIX does not work for CMake on Windows host system, it actually needs a prefix instead
         if (CMAKE_HOST_WIN32)
             set (CMAKE_SYSTEM_PREFIX_PATH_SAVED ${CMAKE_SYSTEM_PREFIX_PATH})
@@ -200,7 +204,11 @@ else ()
                 # For Non-MSVC compiler the static define is not baked into the export header file so we need to define it for the try_compile below
                 set (COMPILER_STATIC_DEFINE COMPILE_DEFINITIONS -DURHO3D_STATIC_DEFINE)
             else ()
-                set (URHO3D_LIB_TYPE SHARED)
+                if (EXT STREQUAL .js)
+                    set (URHO3D_LIB_TYPE MODULE)
+                else ()
+                    set (URHO3D_LIB_TYPE SHARED)
+                endif ()
                 unset (COMPILER_STATIC_DEFINE)
             endif ()
         endif ()
@@ -232,22 +240,26 @@ else ()
                 endif ()
             endif ()
             set (COMPILER_FLAGS "${COMPILER_32BIT_FLAG} ${CMAKE_REQUIRED_FLAGS}")
-            string (REPLACE .js ";" COMPILER_FLAGS "${COMPILER_FLAGS}")     # Emscripten-specific - revise SmileyHack to inject empty suffix to keep try_compile() happy
-            while (NOT URHO3D_COMPILE_RESULT)
-                try_compile (URHO3D_COMPILE_RESULT ${CMAKE_BINARY_DIR} ${CMAKE_CURRENT_LIST_DIR}/CheckUrhoLibrary.cpp
-                    CMAKE_FLAGS -DCOMPILE_DEFINITIONS:STRING=${COMPILER_FLAGS} -DLINK_LIBRARIES:STRING=${URHO3D_LIBRARIES} -DINCLUDE_DIRECTORIES:STRING=${URHO3D_INCLUDE_DIRS} ${COMPILER_STATIC_DEFINE} ${COMPILER_STATIC_RUNTIME_FLAGS}
-                    OUTPUT_VARIABLE TRY_COMPILE_OUT)
-                if (MSVC AND NOT URHO3D_COMPILE_RESULT AND NOT COMPILER_STATIC_RUNTIME_FLAGS)
-                    # Give a second chance for MSVC to use static runtime flag
-                    if (URHO3D_LIBRARIES_REL)
-                        set (COMPILER_STATIC_RUNTIME_FLAGS COMPILE_DEFINITIONS /MT)
+            if (URHO3D_LIB_TYPE STREQUAL MODULE)
+                # Module library type cannot be test linked so just assume it is a valid Urho3D module for now
+                set (URHO3D_COMPILE_RESULT 1)
+            else ()
+                while (NOT URHO3D_COMPILE_RESULT)
+                    try_compile (URHO3D_COMPILE_RESULT ${CMAKE_BINARY_DIR} ${CMAKE_CURRENT_LIST_DIR}/CheckUrhoLibrary.cpp
+                        CMAKE_FLAGS -DCOMPILE_DEFINITIONS:STRING=${COMPILER_FLAGS} -DLINK_LIBRARIES:STRING=${URHO3D_LIBRARIES} -DINCLUDE_DIRECTORIES:STRING=${URHO3D_INCLUDE_DIRS} ${COMPILER_STATIC_DEFINE} ${COMPILER_STATIC_RUNTIME_FLAGS}
+                        OUTPUT_VARIABLE TRY_COMPILE_OUT)
+                    if (MSVC AND NOT URHO3D_COMPILE_RESULT AND NOT COMPILER_STATIC_RUNTIME_FLAGS)
+                        # Give a second chance for MSVC to use static runtime flag
+                        if (URHO3D_LIBRARIES_REL)
+                            set (COMPILER_STATIC_RUNTIME_FLAGS COMPILE_DEFINITIONS /MT)
+                        else ()
+                            set (COMPILER_STATIC_RUNTIME_FLAGS COMPILE_DEFINITIONS /MTd)
+                        endif ()
                     else ()
-                        set (COMPILER_STATIC_RUNTIME_FLAGS COMPILE_DEFINITIONS /MTd)
+                        break ()    # Other compilers break immediately rendering the while-loop a no-ops
                     endif ()
-                else ()
-                    break ()    # Other compilers break immediately rendering the while-loop a no-ops
-                endif ()
-            endwhile ()
+                endwhile ()
+            endif ()
             set (URHO3D_COMPILE_RESULT ${URHO3D_COMPILE_RESULT} CACHE INTERNAL "FindUrho3D module's compile result")
             if (URHO3D_COMPILE_RESULT)
                 # Auto-discover build options used by the found library and export header

+ 266 - 211
CMake/Modules/UrhoCommon.cmake

@@ -125,7 +125,7 @@ if (RPI)
     link_directories (${VIDEOCORE_LIBRARY_DIRS})
 endif ()
 if (CMAKE_PROJECT_NAME STREQUAL Urho3D)
-    set (URHO3D_LIB_TYPE STATIC CACHE STRING "Specify Urho3D library type, possible values are STATIC (default) and SHARED")
+    set (URHO3D_LIB_TYPE STATIC CACHE STRING "Specify Urho3D library type, possible values are STATIC (default), SHARED, and MODULE; the last value is available for Emscripten only")
     # Non-Windows platforms always use OpenGL, the URHO3D_OPENGL variable will always be forced to TRUE, i.e. it is not an option at all
     # Windows platform has URHO3D_OPENGL as an option, MSVC compiler default to FALSE (i.e. prefers Direct3D) while MinGW compiler default to TRUE
     if (MINGW)
@@ -187,7 +187,7 @@ if (CMAKE_PROJECT_NAME STREQUAL Urho3D)
         set_property (GLOBAL PROPERTY FIND_LIBRARY_USE_LIB64_PATHS ${URHO3D_64BIT})
     endif ()
 else ()
-    set (URHO3D_LIB_TYPE "" CACHE STRING "Specify Urho3D library type, possible values are STATIC (default) and SHARED")
+    set (URHO3D_LIB_TYPE "" CACHE STRING "Specify Urho3D library type, possible values are STATIC (default), SHARED, and MODULE; the last value is available for Emscripten only")
     set (URHO3D_HOME "" CACHE PATH "Path to Urho3D build tree or SDK installation location (downstream project only)")
     if (URHO3D_PCH OR URHO3D_UPDATE_SOURCE_TREE OR URHO3D_TOOLS)
         # Just reference it to suppress "unused variable" CMake warning on downstream projects using this CMake module
@@ -200,7 +200,7 @@ else ()
         include_directories (${URHO3D_INCLUDE_DIRS})
     endif ()
 endif ()
-option (URHO3D_PACKAGING "Enable resources packaging support, on Web platform default to 1, on other platforms default to 0" ${WEB})
+cmake_dependent_option (URHO3D_PACKAGING "Enable resources packaging support" FALSE "NOT WEB" TRUE)
 # Enable profiling by default. If disabled, autoprofileblocks become no-ops and the Profiler subsystem is not instantiated.
 option (URHO3D_PROFILING "Enable profiling support" TRUE)
 # Enable logging by default. If disabled, LOGXXXX macros become no-ops and the Log subsystem is not instantiated.
@@ -290,17 +290,24 @@ if (RPI)
     set (RPI_ABI ${RPI_ABI} CACHE STRING "Specify target ABI (RPI platform only), possible values are armeabi-v6 (default for RPI 1), armeabi-v7a (default for RPI 2), armeabi-v7a with NEON, and armeabi-v7a with VFPV4" FORCE)
 endif ()
 if (EMSCRIPTEN)     # CMAKE_CROSSCOMPILING is always true for Emscripten
+    set (MODULE MODULE)
     set (EMSCRIPTEN_ROOT_PATH "" CACHE PATH "Root path to Emscripten cross-compiler tools (Emscripten only)")
     set (EMSCRIPTEN_SYSROOT "" CACHE PATH "Path to Emscripten system root (Emscripten only)")
     cmake_dependent_option (EMSCRIPTEN_WASM "Enable Binaryen support to generate output to WASM (WebAssembly) format (Emscripten only)" FALSE "NOT EMSCRIPTEN_EMCC_VERSION VERSION_LESS 1.37.3" FALSE)
-    cmake_dependent_option (EMSCRIPTEN_ALLOW_MEMORY_GROWTH "Enable memory growing based on application demand when targeting asm.js, it is not set by default due to performance penalty (Emscripten only)" FALSE "NOT EMSCRIPTEN_WASM" TRUE)   # Allo memory growth by default when targeting WebAssembly since there is no performance penalty as in asm.js mode
+    # Currently Emscripten does not support memory growth with MODULE library type
+    if (URHO3D_LIB_TYPE STREQUAL MODULE)
+        set (DEFAULT_MEMORY_GROWTH FALSE)
+    else ()
+        set (DEFAULT_MEMORY_GROWTH TRUE)
+    endif ()
+    cmake_dependent_option (EMSCRIPTEN_ALLOW_MEMORY_GROWTH "Enable memory growing based on application demand when targeting asm.js, it is not set by default due to performance penalty (Emscripten with STATIC or SHARED library type only)" FALSE "NOT EMSCRIPTEN_WASM AND NOT URHO3D_LIB_TYPE STREQUAL MODULE" ${DEFAULT_MEMORY_GROWTH})   # Allow memory growth by default when targeting WebAssembly since there is no performance penalty as in asm.js mode
     math (EXPR EMSCRIPTEN_TOTAL_MEMORY "128 * 1024 * 1024")
     set (EMSCRIPTEN_TOTAL_MEMORY ${EMSCRIPTEN_TOTAL_MEMORY} CACHE STRING "Specify the total size of memory to be used (Emscripten only); default to 128 MB, must be in multiple of 64 KB when targeting WebAssembly and in multiple of 16 MB when targeting asm.js")
     option (EMSCRIPTEN_SHARE_DATA "Enable sharing data file support (Emscripten only)")
     cmake_dependent_option (EMSCRIPTEN_SHARE_JS "Share the same JS file responsible to load the shared data file (Emscripten only and when enabling sharing data file support only)" FALSE EMSCRIPTEN_SHARE_DATA FALSE)
 endif ()
 # Constrain the build option values in cmake-gui, if applicable
-set_property (CACHE URHO3D_LIB_TYPE PROPERTY STRINGS STATIC SHARED)
+set_property (CACHE URHO3D_LIB_TYPE PROPERTY STRINGS STATIC SHARED ${MODULE})
 if (NOT CMAKE_CONFIGURATION_TYPES)
     set_property (CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS ${URHO3D_BUILD_CONFIGURATIONS})
 endif ()
@@ -368,7 +375,7 @@ endif ()
 if (URHO3D_LIB_TYPE)
     string (TOUPPER ${URHO3D_LIB_TYPE} URHO3D_LIB_TYPE)
 endif ()
-if (NOT URHO3D_LIB_TYPE STREQUAL SHARED)
+if (NOT URHO3D_LIB_TYPE STREQUAL SHARED AND NOT URHO3D_LIB_TYPE STREQUAL MODULE)
     set (URHO3D_LIB_TYPE STATIC)
     if (MSVC)
         # This define will be baked into the export header for MSVC compiler
@@ -628,21 +635,8 @@ else ()
                 endif ()
                 set (CMAKE_C_FLAGS_RELEASE "-Oz -DNDEBUG")
                 set (CMAKE_CXX_FLAGS_RELEASE "-Oz -DNDEBUG")
-                # Linker flags
-                if (EMSCRIPTEN_WASM)
-                    # Allow emitting of code that might trap (for higher performance)
-                    set (WASM_LINKER_FLAGS "-s WASM=1 -s BINARYEN_IMPRECISE=1")  # TODO: BINARYEN_IMPRECISE could be renamed to BINARYEN_EMIT_POTENTIAL_TRAPS or something like that in the coming release)
-                endif ()
-                set (MEMORY_LINKER_FLAGS "-s TOTAL_MEMORY=${EMSCRIPTEN_TOTAL_MEMORY}")
-                if (EMSCRIPTEN_ALLOW_MEMORY_GROWTH)
-                    set (MEMORY_LINKER_FLAGS "${MEMORY_LINKER_FLAGS} -s ALLOW_MEMORY_GROWTH=1")
-                endif ()
-                set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${WASM_LINKER_FLAGS} ${MEMORY_LINKER_FLAGS} -s NO_EXIT_RUNTIME=1 -s ERROR_ON_UNDEFINED_SYMBOLS=1")
                 set (CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} -O3 -s AGGRESSIVE_VARIABLE_ELIMINATION=1")     # Remove variables to make the -O3 regalloc easier
                 set (CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG} -g4")     # Preserve LLVM debug information, show line number debug comments, and generate source maps
-                if (URHO3D_TESTING)
-                    set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} --emrun")  # Inject code into the generated Module object to enable capture of stdout, stderr and exit()
-                endif ()
             endif ()
         elseif (MINGW)
             # MinGW-specific setup
@@ -872,7 +866,13 @@ macro (define_dependency_libs TARGET)
                 if (TARGET ${TARGET}_universal)
                     add_dependencies (${TARGET_NAME} ${TARGET}_universal)
                 endif ()
-                list (APPEND ABSOLUTE_PATH_LIBS ${URHO3D_LIBRARIES})
+                if (URHO3D_LIB_TYPE STREQUAL MODULE)
+                    if (TARGET ${TARGET})
+                        add_dependencies (${TARGET_NAME} ${TARGET})
+                    endif ()
+                else ()
+                    list (APPEND ABSOLUTE_PATH_LIBS ${URHO3D_LIBRARIES})
+                endif ()
             endif ()
         endif ()
     endif ()
@@ -949,6 +949,110 @@ macro (define_source_files)
     endif ()
 endmacro ()
 
+# Macro for defining resource files, should be called after the define_source_files() macro
+macro (define_resource_files)
+    check_source_files ()
+    if (NOT RESOURCE_DIRS)
+        # If the macro caller has not defined the resource dirs then set them based on Urho3D project convention
+        foreach (DIR ${CMAKE_SOURCE_DIR}/bin/CoreData ${CMAKE_SOURCE_DIR}/bin/Data)
+            # Do not assume downstream project always follows Urho3D project convention, so double check if this directory exists before using it
+            if (IS_DIRECTORY ${DIR})
+                list (APPEND RESOURCE_DIRS ${DIR})
+            endif ()
+        endforeach ()
+    endif ()
+    if (URHO3D_PACKAGING AND RESOURCE_DIRS)
+        # Populate all the variables required by resource packaging
+        foreach (DIR ${RESOURCE_DIRS})
+            get_filename_component (NAME ${DIR} NAME)
+            if (ANDROID)
+                set (RESOURCE_${DIR}_PATHNAME ${CMAKE_BINARY_DIR}/assets/${NAME}.pak)
+            else ()
+                set (RESOURCE_${DIR}_PATHNAME ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${NAME}.pak)
+            endif ()
+            list (APPEND RESOURCE_PAKS ${RESOURCE_${DIR}_PATHNAME})
+            if (EMSCRIPTEN AND NOT EMSCRIPTEN_SHARE_DATA)
+                # Set the custom EMCC_OPTION property to preload the *.pak individually
+                set_source_files_properties (${RESOURCE_${DIR}_PATHNAME} PROPERTIES EMCC_OPTION preload-file EMCC_FILE_ALIAS "@/${NAME}.pak --use-preload-cache")
+            endif ()
+        endforeach ()
+        set_property (SOURCE ${RESOURCE_PAKS} PROPERTY GENERATED TRUE)
+        if (WEB)
+            if (EMSCRIPTEN)
+                # Set the custom EMCC_OPTION property to peload the generated shared data file
+                if (EMSCRIPTEN_SHARE_DATA)
+                    set (SHARED_RESOURCE_JS ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${CMAKE_PROJECT_NAME}.js)
+                    if (EMSCRIPTEN_SHARE_JS)
+                        set (PREFIX_JS ${CMAKE_BINARY_DIR}/Source/prefix.js)
+                        set (SHARED_JS ${SHARED_RESOURCE_JS})
+                    else ()
+                        set (PREFIX_JS ${SHARED_RESOURCE_JS})
+                    endif ()
+                    list (APPEND SOURCE_FILES ${PREFIX_JS} ${SHARED_RESOURCE_JS}.data)
+                    set_source_files_properties (${PREFIX_JS} PROPERTIES GENERATED TRUE EMCC_OPTION pre-js)
+                    # Need to check if the destination variable is defined first because this macro could be called by downstream project that does not wish to install anything
+                    if (DEST_BUNDLE_DIR)
+                        install (FILES ${SHARED_JS} ${SHARED_RESOURCE_JS}.data DESTINATION ${DEST_BUNDLE_DIR})
+                    endif ()
+                    # Define a custom command for generating a shared data file
+                    if (RESOURCE_PAKS)
+                        # When sharing a single data file, all main targets are assumed to use a same set of resource paks
+                        foreach (FILE ${RESOURCE_PAKS})
+                            get_filename_component (NAME ${FILE} NAME)
+                            list (APPEND PAK_NAMES ${NAME})
+                        endforeach ()
+                        if (CMAKE_BUILD_TYPE STREQUAL Debug AND EMSCRIPTEN_EMCC_VERSION VERSION_GREATER 1.32.2)
+                            set (SEPARATE_METADATA --separate-metadata)
+                        endif ()
+                        add_custom_command (OUTPUT ${SHARED_RESOURCE_JS}.data
+                            COMMAND ${EMPACKAGER} ${SHARED_RESOURCE_JS}.data --preload ${PAK_NAMES} --js-output=${SHARED_RESOURCE_JS} --use-preload-cache ${SEPARATE_METADATA}
+                            DEPENDS RESOURCE_CHECK ${RESOURCE_PAKS}
+                            WORKING_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}
+                            COMMENT "Generating shared data file")
+                    endif ()
+                endif ()
+            endif ()
+        endif ()
+    endif ()
+    if (XCODE)
+        if (NOT RESOURCE_FILES)
+            # Default app bundle icon
+            set (RESOURCE_FILES ${CMAKE_SOURCE_DIR}/bin/Data/Textures/UrhoIcon.icns)
+            if (IOS)
+                # Default app icon on the iOS home screen
+                list (APPEND RESOURCE_FILES ${CMAKE_SOURCE_DIR}/bin/Data/Textures/UrhoIcon.png)
+            endif ()
+        endif ()
+        # Group them together under 'Resources' in Xcode IDE
+        source_group (Resources FILES ${RESOURCE_DIRS} ${RESOURCE_PAKS} ${RESOURCE_FILES})
+        # But only use either paks or dirs
+        if (RESOURCE_PAKS)
+            set_source_files_properties (${RESOURCE_PAKS} ${RESOURCE_FILES} PROPERTIES MACOSX_PACKAGE_LOCATION Resources)
+        else ()
+            set_source_files_properties (${RESOURCE_DIRS} ${RESOURCE_FILES} PROPERTIES MACOSX_PACKAGE_LOCATION Resources)
+        endif ()
+    endif ()
+    list (APPEND SOURCE_FILES ${RESOURCE_DIRS} ${RESOURCE_PAKS} ${RESOURCE_FILES})
+endmacro()
+
+# Macro fo adding a HTML shell-file when targeting Web platform
+macro (add_html_shell)
+    if (NOT ${ARGN} STREQUAL "")
+        set (SHELL_HTML ${ARGN})
+    else ()
+        # Create Urho3D custom HTML shell that also embeds our own project logo
+        if (NOT EXISTS ${CMAKE_BINARY_DIR}/Source/shell.html)
+            file (READ ${EMSCRIPTEN_ROOT_PATH}/src/shell.html SHELL_HTML)
+            string (REPLACE "<!doctype html>" "<!-- This is a generated file. DO NOT EDIT!-->\n\n<!doctype html>" SHELL_HTML "${SHELL_HTML}")     # Stringify to preserve semicolons
+            string (REPLACE "<body>" "<body>\n\n<a href=\"https://urho3d.github.io\" title=\"Urho3D Homepage\"><img src=\"https://urho3d.github.io/assets/images/logo.png\" alt=\"link to https://urho3d.github.io\" height=\"80\" width=\"160\" /></a>\n" SHELL_HTML "${SHELL_HTML}")
+            file (WRITE ${CMAKE_BINARY_DIR}/Source/shell.html "${SHELL_HTML}")
+        endif ()
+        set (SHELL_HTML ${CMAKE_BINARY_DIR}/Source/shell.html)
+    endif ()
+    list (APPEND SOURCE_FILES ${SHELL_HTML})
+    set_source_files_properties (${SHELL_HTML} PROPERTIES EMCC_OPTION shell-file)
+endmacro ()
+
 include (GenerateExportHeader)
 
 # Macro for precompiling header (On MSVC, the dummy C++ or C implementation file for precompiling the header file would be generated if not already exists)
@@ -1273,6 +1377,7 @@ endmacro ()
 #  LIBS - list of dependent libraries that are built internally in the project
 #  ABSOLUTE_PATH_LIBS - list of dependent libraries that are external to the project
 #  LINK_DEPENDS - list of additional files on which a target binary depends for linking (Makefile-based generator only)
+#  LINK_FLAGS - list of additional link flags
 #  TARGET_PROPERTIES - list of target properties
 macro (setup_executable)
     cmake_parse_arguments (ARG "PRIVATE;TOOL;NODEPS" "" "" ${ARGN})
@@ -1293,10 +1398,24 @@ macro (setup_executable)
     if (NOT ARG_NODEPS)
         define_dependency_libs (Urho3D)
     endif ()
+    if (EMSCRIPTEN)
+        list (APPEND LINK_FLAGS "-s NO_EXIT_RUNTIME=1 -s ERROR_ON_UNDEFINED_SYMBOLS=1 -s TOTAL_MEMORY=${EMSCRIPTEN_TOTAL_MEMORY}")
+        if (EMSCRIPTEN_ALLOW_MEMORY_GROWTH)
+            list (APPEND LINK_FLAGS "-s ALLOW_MEMORY_GROWTH=1")
+        endif ()
+        if (EMSCRIPTEN_WASM)
+            # Allow emitting of code that might trap (for higher performance)
+            list (APPEND LINK_FLAGS "-s WASM=1 -s BINARYEN_IMPRECISE=1")  # TODO: BINARYEN_IMPRECISE could be renamed to BINARYEN_EMIT_POTENTIAL_TRAPS or something like that in the coming release)
+        endif ()
+        if (URHO3D_TESTING)
+            # Inject code into the generated Module object to enable capture of stdout, stderr and exit(); and also to enable processing of request parameters as app's arguments
+            list (APPEND LINK_FLAGS "--emrun")
+        endif ()
+    endif ()
     if (XCODE AND LUAJIT_EXE_LINKER_FLAGS_APPLE)
         list (APPEND TARGET_PROPERTIES XCODE_ATTRIBUTE_OTHER_LDFLAGS[arch=x86_64] "${LUAJIT_EXE_LINKER_FLAGS_APPLE} $(OTHER_LDFLAGS)")    # Xcode universal build linker flags when targeting 64-bit OSX with LuaJIT enabled
     endif ()
-    setup_target ()
+    _setup_target ()
 
     if (URHO3D_SCP_TO_TARGET)
         add_custom_command (TARGET ${TARGET_NAME} POST_BUILD COMMAND scp $<TARGET_FILE:${TARGET_NAME}> ${URHO3D_SCP_TO_TARGET} || exit 0
@@ -1316,12 +1435,24 @@ macro (setup_executable)
         # Make a copy of the D3D DLL to the runtime directory in the build tree
         add_custom_command (TARGET ${TARGET_NAME} POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_if_different ${DIRECT3D_DLL} ${RUNTIME_DIR})
     endif ()
+    if (EMSCRIPTEN AND NOT ARG_NODEPS AND URHO3D_LIB_TYPE STREQUAL MODULE AND RUNTIME_DIR)
+        # Make a copy of the Urho3D module to the runtime directory in the build tree
+        if (TARGET Urho3D)
+            add_custom_command (TARGET ${TARGET_NAME} POST_BUILD
+                COMMAND ${CMAKE_COMMAND} -E copy_if_different $<TARGET_FILE:Urho3D> ${RUNTIME_DIR}
+                COMMAND ${CMAKE_COMMAND} -E copy_if_different $<TARGET_FILE:Urho3D>.mem ${RUNTIME_DIR})
+        else ()
+            add_custom_command (TARGET ${TARGET_NAME} POST_BUILD
+                COMMAND ${CMAKE_COMMAND} -E copy_if_different ${URHO3D_LIBRARIES} ${RUNTIME_DIR}
+                COMMAND ${CMAKE_COMMAND} -E copy_if_different ${URHO3D_LIBRARIES}.mem ${RUNTIME_DIR})
+        endif ()
+    endif ()
     # Need to check if the destination variable is defined first because this macro could be called by downstream project that does not wish to install anything
     if (NOT ARG_PRIVATE)
         if (WEB AND DEST_BUNDLE_DIR)
             set (LOCATION $<TARGET_FILE_DIR:${TARGET_NAME}>)
             unset (FILES)
-            foreach (EXT data html html.map html.mem js)
+            foreach (EXT data html html.map html.mem js wasm)
                 list (APPEND FILES ${LOCATION}/${TARGET_NAME}.${EXT})
             endforeach ()
             install (FILES ${FILES} DESTINATION ${DEST_BUNDLE_DIR} OPTIONAL)    # We get html.map or html.mem depend on the build configuration
@@ -1354,6 +1485,7 @@ endmacro ()
 #  LIBS - list of dependent libraries that are built internally in the project
 #  ABSOLUTE_PATH_LIBS - list of dependent libraries that are external to the project
 #  LINK_DEPENDS - list of additional files on which a target binary depends for linking (Makefile-based generator only)
+#  LINK_FLAGS - list of additional link flags
 #  TARGET_PROPERTIES - list of target properties
 macro (setup_library)
     cmake_parse_arguments (ARG NODEPS "" "" ${ARGN})
@@ -1366,7 +1498,7 @@ macro (setup_library)
     if (XCODE AND LUAJIT_SHARED_LINKER_FLAGS_APPLE AND LIB_TYPE STREQUAL SHARED_LIBRARY)
         list (APPEND TARGET_PROPERTIES XCODE_ATTRIBUTE_OTHER_LDFLAGS[arch=x86_64] "${LUAJIT_SHARED_LINKER_FLAGS_APPLE} $(OTHER_LDFLAGS)")    # Xcode universal build linker flags when targeting 64-bit OSX with LuaJIT enabled
     endif ()
-    setup_target ()
+    _setup_target ()
 
     # Setup the compiler flags for building shared library
     if (LIB_TYPE STREQUAL SHARED_LIBRARY)
@@ -1403,109 +1535,11 @@ endmacro ()
 #  LIBS - list of dependent libraries that are built internally in the project
 #  ABSOLUTE_PATH_LIBS - list of dependent libraries that are external to the project
 #  LINK_DEPENDS - list of additional files on which a target binary depends for linking (Makefile-based generator only)
+#  LINK_FLAGS - list of additional link flags
 #  TARGET_PROPERTIES - list of target properties
 macro (setup_main_executable)
     cmake_parse_arguments (ARG "NOBUNDLE;MACOSX_BUNDLE;WIN32" "" "" ${ARGN})
-
-    # Define resources
-    if (NOT RESOURCE_DIRS)
-        # If the macro caller has not defined the resource dirs then set them based on Urho3D project convention
-        foreach (DIR ${CMAKE_SOURCE_DIR}/bin/CoreData ${CMAKE_SOURCE_DIR}/bin/Data)
-            # Do not assume downstream project always follows Urho3D project convention, so double check if this directory exists before using it
-            if (IS_DIRECTORY ${DIR})
-                list (APPEND RESOURCE_DIRS ${DIR})
-            endif ()
-        endforeach ()
-    endif ()
-    if (URHO3D_PACKAGING AND RESOURCE_DIRS)
-        # Populate all the variables required by resource packaging
-        foreach (DIR ${RESOURCE_DIRS})
-            get_filename_component (NAME ${DIR} NAME)
-            if (ANDROID)
-                set (RESOURCE_${DIR}_PATHNAME ${CMAKE_BINARY_DIR}/assets/${NAME}.pak)
-            else ()
-                set (RESOURCE_${DIR}_PATHNAME ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${NAME}.pak)
-            endif ()
-            list (APPEND RESOURCE_PAKS ${RESOURCE_${DIR}_PATHNAME})
-            if (EMSCRIPTEN AND NOT EMSCRIPTEN_SHARE_DATA)
-                # Set the custom EMCC_OPTION property to preload the *.pak individually
-                set_source_files_properties (${RESOURCE_${DIR}_PATHNAME} PROPERTIES EMCC_OPTION preload-file EMCC_FILE_ALIAS "@/${NAME}.pak --use-preload-cache")
-            endif ()
-        endforeach ()
-        # Urho3D project builds the PackageTool as required; downstream project uses PackageTool found in the Urho3D build tree or Urho3D SDK
-        find_Urho3d_tool (PACKAGE_TOOL PackageTool
-            HINTS ${CMAKE_BINARY_DIR}/bin/tool ${URHO3D_HOME}/bin/tool
-            DOC "Path to PackageTool" MSG_MODE WARNING)
-        if (CMAKE_PROJECT_NAME STREQUAL Urho3D)
-            set (PACKAGING_DEP DEPENDS PackageTool)
-        endif ()
-        set (PACKAGING_COMMENT " and packaging")
-        set_property (SOURCE ${RESOURCE_PAKS} PROPERTY GENERATED TRUE)
-        if (WEB)
-            if (EMSCRIPTEN)
-                # When generating html as output, check if shell-file is already added in source files list by downstream project
-                if (CMAKE_EXECUTABLE_SUFFIX_CXX STREQUAL .html)
-                    if (NOT CMAKE_PROJECT_NAME STREQUAL Urho3D)
-                        foreach (FILE ${SOURCE_FILES})
-                            get_property (EMCC_OPTION SOURCE ${FILE} PROPERTY EMCC_OPTION)
-                            if (EMCC_OPTION STREQUAL shell-file)
-                                set (SHELL_HTML_FOUND TRUE)
-                                break ()
-                            endif ()
-                        endforeach ()
-                    endif ()
-                    if (NOT SHELL_HTML_FOUND)
-                        # Use custom Urho3D shell.html
-                        set (SHELL_HTML ${CMAKE_BINARY_DIR}/Source/shell.html)
-                        list (APPEND SOURCE_FILES ${SHELL_HTML})
-                        set_source_files_properties (${SHELL_HTML} PROPERTIES EMCC_OPTION shell-file)
-                    endif ()
-                endif ()
-                # Set the custom EMCC_OPTION property to peload the generated shared data file
-                if (EMSCRIPTEN_SHARE_DATA)
-                    set (SHARED_RESOURCE_JS ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${CMAKE_PROJECT_NAME}.js)
-                    if (EMSCRIPTEN_SHARE_JS)
-                        set (PREFIX_JS ${CMAKE_BINARY_DIR}/Source/prefix.js)
-                        set (SHARED_JS ${SHARED_RESOURCE_JS})
-                    else ()
-                        set (PREFIX_JS ${SHARED_RESOURCE_JS})
-                    endif ()
-                    list (APPEND SOURCE_FILES ${PREFIX_JS} ${SHARED_RESOURCE_JS}.data)
-                    set_source_files_properties (${PREFIX_JS} PROPERTIES GENERATED TRUE EMCC_OPTION pre-js)
-                    # Need to check if the destination variable is defined first because this macro could be called by downstream project that does not wish to install anything
-                    if (DEST_BUNDLE_DIR)
-                        install (FILES ${SHARED_JS} ${SHARED_RESOURCE_JS}.data DESTINATION ${DEST_BUNDLE_DIR})
-                    endif ()
-                endif ()
-                # If not using EMRUN then we need to include the emrun_prejs.js manually in order to process the request parameters as arguments correctly
-                if (NOT URHO3D_TESTING)
-                    set (EMRUN_PREJS ${EMSCRIPTEN_ROOT_PATH}/src/emrun_prejs.js)
-                    list (APPEND SOURCE_FILES ${EMRUN_PREJS})
-                    set_source_files_properties (${EMRUN_PREJS} PROPERTIES EMCC_OPTION pre-js)
-                endif ()
-            endif ()
-        endif ()
-    endif ()
-    if (XCODE)
-        if (NOT RESOURCE_FILES)
-            # Default app bundle icon
-            set (RESOURCE_FILES ${CMAKE_SOURCE_DIR}/bin/Data/Textures/UrhoIcon.icns)
-            if (IOS)
-                # Default app icon on the iOS home screen
-                list (APPEND RESOURCE_FILES ${CMAKE_SOURCE_DIR}/bin/Data/Textures/UrhoIcon.png)
-            endif ()
-        endif ()
-        # Group them together under 'Resources' in Xcode IDE
-        source_group (Resources FILES ${RESOURCE_DIRS} ${RESOURCE_PAKS} ${RESOURCE_FILES})
-        # But only use either paks or dirs
-        if (RESOURCE_PAKS)
-            set_source_files_properties (${RESOURCE_PAKS} ${RESOURCE_FILES} PROPERTIES MACOSX_PACKAGE_LOCATION Resources)
-        else ()
-            set_source_files_properties (${RESOURCE_DIRS} ${RESOURCE_FILES} PROPERTIES MACOSX_PACKAGE_LOCATION Resources)
-        endif ()
-    endif ()
-    list (APPEND SOURCE_FILES ${RESOURCE_DIRS} ${RESOURCE_PAKS} ${RESOURCE_FILES})
-
+    define_resource_files ()
     if (ANDROID)
         # Add SDL native init function, SDL_Main() entry point must be defined by one of the source files in ${SOURCE_FILES}
         find_Urho3D_file (ANDROID_MAIN_C_PATH SDL_android_main.c
@@ -1557,30 +1591,121 @@ macro (setup_main_executable)
             endif ()
         elseif (WEB)
             if (EMSCRIPTEN)
-                # Pass additional source files to linker with the supported flags, such as: js-library, pre-js, post-js, embed-file, preload-file, shell-file
+                # Output to HTML when a HTML shell-file is being added in source files list
                 foreach (FILE ${SOURCE_FILES})
                     get_property (EMCC_OPTION SOURCE ${FILE} PROPERTY EMCC_OPTION)
-                    if (EMCC_OPTION)
-                        list (APPEND LINK_DEPENDS ${FILE})
-                        unset (EMCC_FILE_ALIAS)
-                        unset (EMCC_EXCLUDE_FILE)
-                        if (EMCC_OPTION STREQUAL embed-file OR EMCC_OPTION STREQUAL preload-file)
-                            get_property (EMCC_FILE_ALIAS SOURCE ${FILE} PROPERTY EMCC_FILE_ALIAS)
-                            get_property (EMCC_EXCLUDE_FILE SOURCE ${FILE} PROPERTY EMCC_EXCLUDE_FILE)
-                            if (EMCC_EXCLUDE_FILE)
-                                set (EMCC_EXCLUDE_FILE " --exclude-file ${EMCC_EXCLUDE_FILE}")
-                            endif ()
-                        endif ()
-                        set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} --${EMCC_OPTION} ${FILE}${EMCC_FILE_ALIAS}${EMCC_EXCLUDE_FILE}")
+                    if (EMCC_OPTION STREQUAL shell-file)
+                        list (APPEND TARGET_PROPERTIES SUFFIX .html)
+                        break ()
                     endif ()
                 endforeach ()
+                if (URHO3D_TESTING)
+                    # Auto adding the HTML shell-file during testing with emrun, if it has not been added yet
+                    if (NOT EMCC_OPTION STREQUAL shell-file)
+                        add_html_shell ()
+                        list (APPEND TARGET_PROPERTIES SUFFIX .html)
+                    endif ()
+                else ()
+                    # If not using EMRUN then we need to include the emrun_prejs.js manually in order to process the request parameters as app's arguments correctly
+                    set (EMRUN_PREJS ${EMSCRIPTEN_ROOT_PATH}/src/emrun_prejs.js)
+                    list (APPEND SOURCE_FILES ${EMRUN_PREJS})
+                    set_source_files_properties (${EMRUN_PREJS} PROPERTIES EMCC_OPTION pre-js)
+                endif ()
             endif ()
         endif ()
         setup_executable (${EXE_TYPE} ${ARG_UNPARSED_ARGUMENTS})
     endif ()
 
-    # Define a custom target for resource modification checking and resource packaging (if enabled)
+    # Define a custom command for stripping the main target executable (or shared library for Android) for Release build configuration
+    # Exclude multi-config generators, plus MSVC explicitly since it could also be used through NMake which is not multi-config,
+    # but MSVC does not have a strip command
+    if (CMAKE_BUILD_TYPE STREQUAL Release AND NOT WEB AND NOT MSVC)
+        add_custom_command (TARGET ${TARGET_NAME} POST_BUILD COMMAND ${CMAKE_STRIP} $<TARGET_FILE:${TARGET_NAME}>)
+    endif ()
+endmacro ()
+
+# Macro for setting up dependency lib for compilation and linking of a target (to be used internally)
+macro (_setup_target)
+    # Include directories
+    include_directories (${INCLUDE_DIRS})
+    # Link libraries
+    define_dependency_libs (${TARGET_NAME})
+    target_link_libraries (${TARGET_NAME} ${ABSOLUTE_PATH_LIBS} ${LIBS})
+    # Enable PCH if requested
+    if (${TARGET_NAME}_HEADER_PATHNAME)
+        enable_pch (${${TARGET_NAME}_HEADER_PATHNAME})
+    endif ()
+    # Extra compiler flags for Xcode which are dynamically changed based on active arch in order to support Mach-O universal binary targets
+    # We don't add the ABI flag for Xcode because it automatically passes '-arch i386' compiler flag when targeting 32 bit which does the same thing as '-m32'
+    if (XCODE)
+        # Speed up build when in Debug configuration by building active arch only
+        list (FIND TARGET_PROPERTIES XCODE_ATTRIBUTE_ONLY_ACTIVE_ARCH ATTRIBUTE_ALREADY_SET)
+        if (ATTRIBUTE_ALREADY_SET EQUAL -1)
+            list (APPEND TARGET_PROPERTIES XCODE_ATTRIBUTE_ONLY_ACTIVE_ARCH $<$<CONFIG:Debug>:YES>)
+        endif ()
+        if (NOT URHO3D_SSE)
+            # Nullify the Clang default so that it is consistent with GCC
+            list (APPEND TARGET_PROPERTIES XCODE_ATTRIBUTE_OTHER_CFLAGS[arch=i386] "-mno-sse $(OTHER_CFLAGS)")
+            list (APPEND TARGET_PROPERTIES XCODE_ATTRIBUTE_OTHER_CPLUSPLUSFLAGS[arch=i386] "-mno-sse $(OTHER_CPLUSPLUSFLAGS)")
+        endif ()
+    endif ()
+    # Extra linker flags for Emscripten
+    if (EMSCRIPTEN)
+        # Pass EMCC-specifc setting to differentiate between main and side modules
+        if (URHO3D_LIB_TYPE STREQUAL MODULE)
+            if (${TARGET_NAME} STREQUAL Urho3D)
+                list (APPEND LINK_FLAGS "-s MAIN_MODULE=2")      # Main module has standard libs statically linked with dead code elimination
+            else ()
+                list (APPEND LINK_FLAGS "-s SIDE_MODULE=1")
+            endif ()
+        endif ()
+        # Pass additional source files to linker with the supported flags, such as: js-library, pre-js, post-js, embed-file, preload-file, shell-file
+        foreach (FILE ${SOURCE_FILES})
+            get_property (EMCC_OPTION SOURCE ${FILE} PROPERTY EMCC_OPTION)
+            if (EMCC_OPTION)
+                unset (EMCC_FILE_ALIAS)
+                unset (EMCC_EXCLUDE_FILE)
+                if (EMCC_OPTION STREQUAL embed-file OR EMCC_OPTION STREQUAL preload-file)
+                    get_property (EMCC_FILE_ALIAS SOURCE ${FILE} PROPERTY EMCC_FILE_ALIAS)
+                    get_property (EMCC_EXCLUDE_FILE SOURCE ${FILE} PROPERTY EMCC_EXCLUDE_FILE)
+                    if (EMCC_EXCLUDE_FILE)
+                        set (EMCC_EXCLUDE_FILE " --exclude-file ${EMCC_EXCLUDE_FILE}")
+                    else ()
+                        list (APPEND LINK_DEPENDS ${FILE})
+                    endif ()
+                endif ()
+                list (APPEND LINK_FLAGS "--${EMCC_OPTION} ${FILE}${EMCC_FILE_ALIAS}${EMCC_EXCLUDE_FILE}")
+            endif ()
+        endforeach ()
+    endif ()
+    # Set additional linker dependencies (only work for Makefile-based generator according to CMake documentation)
+    if (LINK_DEPENDS)
+        string (REPLACE ";" "\;" LINK_DEPENDS "${LINK_DEPENDS}")        # Stringify for string replacement
+        list (APPEND TARGET_PROPERTIES LINK_DEPENDS "${LINK_DEPENDS}")  # Stringify with semicolons already escaped
+        unset (LINK_DEPENDS)
+    endif ()
+    # Set additional linker flags
+    if (LINK_FLAGS)
+        string (REPLACE ";" " " LINK_FLAGS "${LINK_FLAGS}")
+        list (APPEND TARGET_PROPERTIES LINK_FLAGS ${LINK_FLAGS})
+        unset (LINK_FLAGS)
+    endif ()
+    if (TARGET_PROPERTIES)
+        set_target_properties (${TARGET_NAME} PROPERTIES ${TARGET_PROPERTIES})
+        unset (TARGET_PROPERTIES)
+    endif ()
+    # Setup custom resource checker target
     if ((EXE_TYPE STREQUAL MACOSX_BUNDLE OR URHO3D_PACKAGING) AND RESOURCE_DIRS)
+        if (URHO3D_PACKAGING)
+            # Urho3D project builds the PackageTool as required; downstream project uses PackageTool found in the Urho3D build tree or Urho3D SDK
+            find_Urho3d_tool (PACKAGE_TOOL PackageTool
+                HINTS ${CMAKE_BINARY_DIR}/bin/tool ${URHO3D_HOME}/bin/tool
+                DOC "Path to PackageTool" MSG_MODE WARNING)
+            if (CMAKE_PROJECT_NAME STREQUAL Urho3D)
+                set (PACKAGING_DEP DEPENDS PackageTool)
+            endif ()
+            set (PACKAGING_COMMENT " and packaging")
+        endif ()
         # Share a same custom target that checks for a same resource dirs list
         foreach (DIR ${RESOURCE_DIRS})
             string (MD5 MD5 ${DIR})
@@ -1618,68 +1743,7 @@ macro (setup_main_executable)
         add_dependencies (${TARGET_NAME} ${RESOURCE_CHECK_${MD5ALL}})
     endif ()
 
-    # Define a custom command for generating a shared data file (if enabled)
-    if (EMSCRIPTEN_SHARE_DATA AND RESOURCE_PAKS)
-        # When sharing a single data file, all main targets are assumed to use a same set of resource paks
-        foreach (FILE ${RESOURCE_PAKS})
-            get_filename_component (NAME ${FILE} NAME)
-            list (APPEND PAK_NAMES ${NAME})
-        endforeach ()
-        if (CMAKE_BUILD_TYPE STREQUAL Debug AND EMSCRIPTEN_EMCC_VERSION VERSION_GREATER 1.32.2)
-            set (SEPARATE_METADATA --separate-metadata)
-        endif ()
-        add_custom_command (OUTPUT ${SHARED_RESOURCE_JS}.data
-            COMMAND ${EMPACKAGER} ${SHARED_RESOURCE_JS}.data --preload ${PAK_NAMES} --js-output=${SHARED_RESOURCE_JS} --use-preload-cache ${SEPARATE_METADATA}
-            DEPENDS RESOURCE_CHECK ${RESOURCE_PAKS}
-            WORKING_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}
-            COMMENT "Generating shared data file")
-    endif ()
-
-    # Define a custom command for stripping the main target executable (or shared library for Android) for Release build configuration
-    # Exclude multi-config generators, plus MSVC explicitly since it could also be used through NMake which is not multi-config,
-    # but MSVC does not have a strip command
-    if (CMAKE_BUILD_TYPE STREQUAL Release AND NOT WEB AND NOT MSVC)
-        add_custom_command (TARGET ${TARGET_NAME} POST_BUILD COMMAND ${CMAKE_STRIP} $<TARGET_FILE:${TARGET_NAME}>)
-    endif ()
-endmacro ()
-
-# Macro for setting up dependency lib for compilation and linking of a target
-macro (setup_target)
-    # Include directories
-    include_directories (${INCLUDE_DIRS})
-    # Link libraries
-    define_dependency_libs (${TARGET_NAME})
-    target_link_libraries (${TARGET_NAME} ${ABSOLUTE_PATH_LIBS} ${LIBS})
-    # Enable PCH if requested
-    if (${TARGET_NAME}_HEADER_PATHNAME)
-        enable_pch (${${TARGET_NAME}_HEADER_PATHNAME})
-    endif ()
-    # Set additional linker dependencies (only work for Makefile-based generator according to CMake documentation)
-    if (LINK_DEPENDS)
-        string (REPLACE ";" "\;" LINK_DEPENDS "${LINK_DEPENDS}")        # Stringify for string replacement
-        list (APPEND TARGET_PROPERTIES LINK_DEPENDS "${LINK_DEPENDS}")  # Stringify with semicolons already escaped
-        unset (LINK_DEPENDS)
-    endif ()
-    # Extra compiler flags for Xcode which are dynamically changed based on active arch in order to support Mach-O universal binary targets
-    # We don't add the ABI flag for Xcode because it automatically passes '-arch i386' compiler flag when targeting 32 bit which does the same thing as '-m32'
-    if (XCODE)
-        # Speed up build when in Debug configuration by building active arch only
-        list (FIND TARGET_PROPERTIES XCODE_ATTRIBUTE_ONLY_ACTIVE_ARCH ATTRIBUTE_ALREADY_SET)
-        if (ATTRIBUTE_ALREADY_SET EQUAL -1)
-            list (APPEND TARGET_PROPERTIES XCODE_ATTRIBUTE_ONLY_ACTIVE_ARCH $<$<CONFIG:Debug>:YES>)
-        endif ()
-        if (NOT URHO3D_SSE)
-            # Nullify the Clang default so that it is consistent with GCC
-            list (APPEND TARGET_PROPERTIES XCODE_ATTRIBUTE_OTHER_CFLAGS[arch=i386] "-mno-sse $(OTHER_CFLAGS)")
-            list (APPEND TARGET_PROPERTIES XCODE_ATTRIBUTE_OTHER_CPLUSPLUSFLAGS[arch=i386] "-mno-sse $(OTHER_CPLUSPLUSFLAGS)")
-        endif ()
-    endif ()
-    if (TARGET_PROPERTIES)
-        set_target_properties (${TARGET_NAME} PROPERTIES ${TARGET_PROPERTIES})
-        unset (TARGET_PROPERTIES)
-    endif ()
-
-    # Workaround CMake/Xcode generator bug where it always appends '/build' path element to SYMROOT attribute and as such the items in Products are always rendered as red in the Xcode IDE as if they are not yet built
+    # Workaround CMake/Xcode generator bug where it always appends '/build' path element to SYMROOT attribute and as such the items in Products are always rendered as red in the Xcode as if they are not yet built
     if (NOT DEFINED ENV{TRAVIS})
         if (XCODE AND NOT CMAKE_PROJECT_NAME MATCHES ^Urho3D-ExternalProject-)
             file (MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/build)
@@ -1691,7 +1755,7 @@ macro (setup_target)
                 WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/build)
         endif ()
     endif ()
-endmacro ()
+endmacro()
 
 # Macro for setting up a test case
 macro (setup_test)
@@ -1752,17 +1816,8 @@ if (ANDROID)
         endif ()
     endforeach ()
 elseif (WEB)
-    # Create Urho3D custom HTML shell that also embeds our own project logo
-    if (EMSCRIPTEN)
-        if (NOT EXISTS ${CMAKE_BINARY_DIR}/Source/shell.html)
-            file (READ ${EMSCRIPTEN_ROOT_PATH}/src/shell.html SHELL_HTML)
-            string (REPLACE "<!doctype html>" "<!-- This is a generated file. DO NOT EDIT!-->\n\n<!doctype html>" SHELL_HTML "${SHELL_HTML}")     # Stringify to preserve semicolons
-            string (REPLACE "<body>" "<body>\n\n<a href=\"https://urho3d.github.io\" title=\"Urho3D Homepage\"><img src=\"https://urho3d.github.io/assets/images/logo.png\" alt=\"link to https://urho3d.github.io\" height=\"80\" width=\"160\" /></a>\n" SHELL_HTML "${SHELL_HTML}")
-            file (WRITE ${CMAKE_BINARY_DIR}/Source/shell.html "${SHELL_HTML}")
-        endif ()
-        if (EMSCRIPTEN_SHARE_JS AND NOT EXISTS ${CMAKE_BINARY_DIR}/Source/prefix.js)
-            file (WRITE ${CMAKE_BINARY_DIR}/Source/prefix.js "var Module;if(typeof Module==='undefined')Module=eval('(function(){try{return Module||{}}catch(e){return{}}})()');var s=document.createElement('script');s.src='${CMAKE_PROJECT_NAME}.js';document.body.appendChild(s);Module['preRun'].push(function(){Module['addRunDependency']('${CMAKE_PROJECT_NAME}.js.loader')});s.onload=function(){Module['removeRunDependency']('${CMAKE_PROJECT_NAME}.js.loader')};")
-        endif ()
+    if (EMSCRIPTEN_SHARE_JS AND NOT EXISTS ${CMAKE_BINARY_DIR}/Source/prefix.js)
+        file (WRITE ${CMAKE_BINARY_DIR}/Source/prefix.js "var Module;if(typeof Module==='undefined')Module=eval('(function(){try{return Module||{}}catch(e){return{}}})()');var s=document.createElement('script');s.src='${CMAKE_PROJECT_NAME}.js';document.body.appendChild(s);Module['preRun'].push(function(){Module['addRunDependency']('${CMAKE_PROJECT_NAME}.js.loader')});s.onload=function(){Module['removeRunDependency']('${CMAKE_PROJECT_NAME}.js.loader')};")
     endif ()
 else ()
     # Create symbolic links in the build tree

+ 4 - 5
CMake/Toolchains/Emscripten.cmake

@@ -154,14 +154,13 @@ foreach (LANG C CXX)
     set (CMAKE_${LANG}_ABI_COMPILED TRUE)
     set (CMAKE_${LANG}_SIZEOF_DATA_PTR 4)   # Assume it is always 32-bit for now (we could have used our CheckCompilerToolChains.cmake module here)
     # We could not set CMAKE_EXECUTABLE_SUFFIX directly because CMake processes platform configuration files after the toolchain file and since we tell CMake that we are cross-compiling for 'Linux' platform (Emscripten is not a valid platform yet in CMake) via CMAKE_SYSTEM_NAME variable, as such CMake force initializes the CMAKE_EXECUTABLE_SUFFIX to empty string (as expected for Linux platform); To workaround it we have to use CMAKE_EXECUTABLE_SUFFIX_C and CMAKE_EXECUTABLE_SUFFIX_CXX instead, which are fortunately not being touched by platform configuration files
-    if (NOT DEFINED CMAKE_EXECUTABLE_SUFFIX_${LANG})
-        set (CMAKE_EXECUTABLE_SUFFIX_${LANG} .html)
-    endif ()
+    set (CMAKE_EXECUTABLE_SUFFIX_${LANG} .js)
+    set (CMAKE_SHARED_LIBRARY_SUFFIX_${LANG} .bc)   # "linked" LLVM bitcode
+    set (CMAKE_SHARED_MODULE_SUFFIX_${LANG} .js)    # side module
 endforeach ()
 
 # Set required compiler flags for various internal CMake checks which rely on the compiler/linker error to be occured for the check to be performed correctly
-# The executable suffix needs to be .js for the below Emscripten-specific compiler setting to be effective
-set (CMAKE_REQUIRED_FLAGS "-s ERROR_ON_UNDEFINED_SYMBOLS=1;-DSmileyHack=byYaoWT;-DCMAKE_EXECUTABLE_SUFFIX_C=.js;-DCMAKE_EXECUTABLE_SUFFIX_CXX=.js")
+set (CMAKE_REQUIRED_FLAGS "-s ERROR_ON_UNDEFINED_SYMBOLS=1")
 
 # Use response files on Windows host
 if (CMAKE_HOST_WIN32)

+ 4 - 3
Docs/GettingStarted.dox

@@ -125,7 +125,7 @@ A number of build options can be defined when invoking the build scripts or when
 |URHO3D_SSE           |*|Enable SSE/SSE2 instruction set (32-bit Web and Intel platforms only, including Android on Intel Atom); default to true on Intel and false on Web platform; the effective SSE level could be higher, see also URHO3D_DEPLOYMENT_TARGET and CMAKE_OSX_DEPLOYMENT_TARGET build options|
 |URHO3D_MINIDUMPS     |1|Enable minidumps on crash (VS only)|
 |URHO3D_FILEWATCHER   |1|Enable filewatcher support|
-|URHO3D_PACKAGING     |*|Enable resources packaging support, on Web platform default to 1, on other platforms default to 0|
+|URHO3D_PACKAGING     |0|Enable resources packaging support|
 |URHO3D_PROFILING     |1|Enable profiling support|
 |URHO3D_LOGGING       |1|Enable logging support|
 |URHO3D_THREADING     |*|Enable thread support, on Web platform default to 0, on other platforms default to 1|
@@ -136,7 +136,7 @@ A number of build options can be defined when invoking the build scripts or when
 |URHO3D_STATIC_RUNTIME|0|Use static C/C++ runtime libraries and eliminate the need for runtime DLLs installation (VS only)|
 |URHO3D_WIN32_CONSOLE |0|Use console main() instead of WinMain() as entry point when setting up Windows executable targets (Windows platform only)|
 |URHO3D_MACOSX_BUNDLE |0|Use MACOSX_BUNDLE when setting up macOS executable targets (macOS platform only)|
-|URHO3D_LIB_TYPE      |STATIC|Specify Urho3D library type, possible values are STATIC (default) and SHARED|
+|URHO3D_LIB_TYPE      |STATIC|Specify Urho3D library type, possible values are STATIC (default), SHARED, and MODULE; the last value is available for Emscripten only|
 |URHO3D_SCP_TO_TARGET |-|Use scp to transfer executables to target system (non-Android cross-compiling build only), SSH digital key must be setup first for this to work, typical value has a pattern of usr@tgt:remote-loc|
 |URHO3D_UPDATE_SOURCE_TREE|0|Enable commands to copy back some of the generated build artifacts from build tree to source tree to facilitate devs to push them as part of a commit (for library devs with push right only)|
 |URHO3D_USE_LIB64_RPM |0|Enable 64-bit RPM CPack generator using /usr/lib64 and disable all other generators (Debian-based host only, which uses /usr/lib by default)|
@@ -163,7 +163,7 @@ A number of build options can be defined when invoking the build scripts or when
 |EMSCRIPTEN_ROOT_PATH |-|Root path to Emscripten cross-compiler tools (Emscripten only)|
 |EMSCRIPTEN_SYSROOT   |-|Path to Emscripten system root (Emscripten only)|
 |EMSCRIPTEN_WASM      |0|Enable Binaryen support to generate output to WASM (WebAssembly) format (Emscripten only)|
-|EMSCRIPTEN_ALLOW_MEMORY_GROWTH|*|Enable memory growing based on application demand when targeting asm.js, it is not set by default due to performance penalty (Emscripten only)|
+|EMSCRIPTEN_ALLOW_MEMORY_GROWTH|*|Enable memory growing based on application demand when targeting asm.js, it is not set by default due to performance penalty (Emscripten with STATIC or SHARED library type only)|
 |EMSCRIPTEN_TOTAL_MEMORY|*|Specify the total size of memory to be used (Emscripten only); default to 128 MB, must be in multiple of 64 KB when targeting WebAssembly and in multiple of 16 MB when targeting asm.js|
 |EMSCRIPTEN_SHARE_DATA|0|Enable sharing data file support (Emscripten only)|
 |EMSCRIPTEN_SHARE_JS  |0|Share the same JS file responsible to load the shared data file (Emscripten only and when enabling sharing data file support only)|
@@ -302,6 +302,7 @@ If CMake complains that emcc is not able to compile a test program, try reactiva
 \subsection Emscripten_experimental_build_options Experimental build options
 
 - EMSCRIPTEN_WASM=1. Enabling this build option to target WebAssembly. Currently the WASM output requires Firefox Nightly or Chrome Canary to run.
+- URHO3D_LIB_TYPE=MODULE. For fast iteration during development time. This build option should be avoided for for production due to reduce throughput.
 
 \section Building_64bit Native 64bit build
 

+ 2 - 1
Docs/Urho3D.dox

@@ -1078,9 +1078,10 @@ From 1.6 to master:
 - UIElement::LoadChildXML() now returns the created element on success, instead of a boolean.
 - Rendertargets have gained the ability to have automatically regenerated mipmaps. Screen buffers received from the Renderer subsystem have mipmaps off, but for manually created rendertargets the default is mipmaps on, like for ordinary textures. Use SetNumLevels(1) to disable.
 - The shader function GetWorldTangent() now returns a 4-component vector.
-- Build system - the "Urho3D-CMake-common.cmake" file is now renamed to "UrhoCommon.cmake".
 - StaticModel::SetModel() will no longer warn and redirect to AnimatedModel::SetModel() if the wrong function is called from C++ code. The AngelScript API will instead redirect properly without producing a warning.
 - Graphics::SetMode(), Graphics::GetDesktopResolution() and Graphics::GetResolutions() have gained an extra parameter to specify the monitor to use. Use Graphics::GetMonitorCount() to get the number of attached monitors. Monitor number 0 means the default primary monitor.
+- Build system - the "Urho3D-CMake-common.cmake" file is now renamed to "UrhoCommon.cmake".
+- Build system - downstream project is now responsible to add the HTML shell-file by calling the add_html_shell() macro in order to generate the HTML output when targeting Web platform, i.e. the build system defaults to JS output now, except when URHO3D_TESTING build option is set. When URHO3D_TESTING is set then it is assumed the output should be test runnable by using emrun, therefore the build system will automatically add the default HTML shell-file if none has been added yet.
 */
 
 }

+ 1 - 1
Rakefile

@@ -54,7 +54,7 @@ task :cmake do
   platform = 'native'
   build_options = ''
   # TODO: Need to find a way to automatically populate the array with all the Urho3D supported build options, at the moment it only contains those being used in CI
-  ['URHO3D_64BIT', 'URHO3D_LIB_TYPE', 'URHO3D_STATIC_RUNTIME', 'URHO3D_PCH', 'URHO3D_BINDINGS', 'URHO3D_OPENGL', 'URHO3D_D3D11', 'URHO3D_TESTING', 'URHO3D_TEST_TIMEOUT', 'URHO3D_UPDATE_SOURCE_TREE', 'URHO3D_TOOLS', 'URHO3D_DEPLOYMENT_TARGET', 'URHO3D_USE_LIB64_RPM', 'CMAKE_BUILD_TYPE', 'CMAKE_OSX_DEPLOYMENT_TARGET', 'IOS', 'IPHONEOS_DEPLOYMENT_TARGET', 'WIN32', 'MINGW', 'ANDROID', 'ANDROID_ABI', 'ANDROID_NATIVE_API_LEVEL', 'ANDROID_TOOLCHAIN_NAME', 'RPI', 'RPI_ABI', 'ARM', 'ARM_ABI_FLAGS', 'WEB', 'EMSCRIPTEN_SHARE_DATA', 'EMSCRIPTEN_SHARE_JS', 'EMSCRIPTEN_WASM', 'EMSCRIPTEN_EMRUN_BROWSER', 'CMAKE_EXECUTABLE_SUFFIX_CXX'].each { |var|
+  ['URHO3D_64BIT', 'URHO3D_LIB_TYPE', 'URHO3D_STATIC_RUNTIME', 'URHO3D_PCH', 'URHO3D_BINDINGS', 'URHO3D_OPENGL', 'URHO3D_D3D11', 'URHO3D_TESTING', 'URHO3D_TEST_TIMEOUT', 'URHO3D_UPDATE_SOURCE_TREE', 'URHO3D_TOOLS', 'URHO3D_DEPLOYMENT_TARGET', 'URHO3D_USE_LIB64_RPM', 'CMAKE_BUILD_TYPE', 'CMAKE_OSX_DEPLOYMENT_TARGET', 'IOS', 'IPHONEOS_DEPLOYMENT_TARGET', 'WIN32', 'MINGW', 'ANDROID', 'ANDROID_ABI', 'ANDROID_NATIVE_API_LEVEL', 'ANDROID_TOOLCHAIN_NAME', 'RPI', 'RPI_ABI', 'ARM', 'ARM_ABI_FLAGS', 'WEB', 'EMSCRIPTEN_SHARE_DATA', 'EMSCRIPTEN_SHARE_JS', 'EMSCRIPTEN_WASM', 'EMSCRIPTEN_EMRUN_BROWSER'].each { |var|
     ARGV << "#{var}=\"#{ENV[var]}\"" if ENV[var] && !ARGV.find { |arg| /#{var}=/ =~ arg }
   }
   ARGV.each { |option|

+ 6 - 4
Source/Urho3D/CMakeLists.txt

@@ -323,9 +323,6 @@ if (NOT ANDROID AND NOT WEB)
     else ()
         message (FATAL_ERROR "The .soversion file is corrupted. It should contain a version number with this format major(0xFFFF).minor(0xFF).patch-level(0xFF). e.g.: 0.1.2")
     endif ()
-elseif (EMSCRIPTEN)
-    # Emscripten does not support generation of shared library in a conventional sense, it just produces "linked" LLVM bitcode
-    set (CMAKE_SHARED_LIBRARY_SUFFIX ".bc")
 endif ()
 if (IOS)
     # Add a custom target to build Mach-O universal binary consisting of iphoneos (universal ARM archs including 'arm64' if 64-bit is enabled) and iphonesimulator (i386 arch and also x86_64 arch if 64-bit is enabled)
@@ -335,6 +332,11 @@ if (IOS)
         WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
         COMMENT "Creating Mach-O universal binary library consisting of both iphoneos and iphonesimulator archs")
     install (FILES $<TARGET_FILE:${TARGET_NAME}> DESTINATION ${DEST_LIBRARY_DIR})
+elseif (EMSCRIPTEN)
+    install (TARGETS ${TARGET_NAME} LIBRARY DESTINATION ${DEST_LIBRARY_DIR} PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ ARCHIVE DESTINATION ${DEST_LIBRARY_DIR})
+    if (URHO3D_LIB_TYPE STREQUAL MODULE)
+        install (FILES $<TARGET_FILE:${TARGET_NAME}>.mem DESTINATION ${DEST_LIBRARY_DIR})
+    endif ()
 else ()
     install (TARGETS ${TARGET_NAME} RUNTIME DESTINATION ${DEST_RUNTIME_DIR} LIBRARY DESTINATION ${DEST_LIBRARY_DIR} ARCHIVE DESTINATION ${DEST_LIBRARY_DIR})
 endif ()
@@ -436,7 +438,7 @@ if (NOT XCODE AND NOT MSVC)
     endif ()
 endif ()
 # Use PIC on platforms that support it (shared library type has this property set to true by default, so we only have to deal with those static ones that the shared library links against)
-if (URHO3D_LIB_TYPE STREQUAL SHARED)
+if (NOT URHO3D_LIB_TYPE STREQUAL STATIC)
     set_target_properties (${STATIC_LIBRARY_TARGETS} PROPERTIES POSITION_INDEPENDENT_CODE true)
 endif ()