draco_emscripten.cmake 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  1. if(DRACO_CMAKE_DRACO_EMSCRIPTEN_CMAKE_)
  2. return()
  3. endif() # DRACO_CMAKE_DRACO_EMSCRIPTEN_CMAKE_
  4. # Checks environment for Emscripten prerequisites.
  5. macro(draco_check_emscripten_environment)
  6. if(NOT PYTHONINTERP_FOUND)
  7. message(
  8. FATAL_ERROR
  9. "Python required for Emscripten builds, but cmake cannot find it.")
  10. endif()
  11. if(NOT EXISTS "$ENV{EMSCRIPTEN}")
  12. message(
  13. FATAL_ERROR
  14. "The EMSCRIPTEN environment variable must be set. See README.md.")
  15. endif()
  16. endmacro()
  17. # Obtains the required Emscripten flags for Draco targets.
  18. macro(draco_get_required_emscripten_flags)
  19. set(em_FLAG_LIST_VAR)
  20. set(em_flags)
  21. set(em_single_arg_opts FLAG_LIST_VAR)
  22. set(em_multi_arg_opts)
  23. cmake_parse_arguments(em "${em_flags}" "${em_single_arg_opts}"
  24. "${em_multi_arg_opts}" ${ARGN})
  25. if(NOT em_FLAG_LIST_VAR)
  26. message(FATAL "draco_get_required_emscripten_flags: FLAG_LIST_VAR required")
  27. endif()
  28. if(DRACO_JS_GLUE)
  29. unset(required_flags)
  30. list(APPEND ${em_FLAG_LIST_VAR} "-sALLOW_MEMORY_GROWTH=1")
  31. list(APPEND ${em_FLAG_LIST_VAR} "-Wno-almost-asm")
  32. list(APPEND ${em_FLAG_LIST_VAR} "--memory-init-file" "0")
  33. list(APPEND ${em_FLAG_LIST_VAR} "-fno-omit-frame-pointer")
  34. list(APPEND ${em_FLAG_LIST_VAR} "-sMODULARIZE=1")
  35. list(APPEND ${em_FLAG_LIST_VAR} "-sNO_FILESYSTEM=1")
  36. list(APPEND ${em_FLAG_LIST_VAR} "-sEXPORTED_RUNTIME_METHODS=[]")
  37. list(APPEND ${em_FLAG_LIST_VAR} "-sPRECISE_F32=1")
  38. list(APPEND ${em_FLAG_LIST_VAR} "-sNODEJS_CATCH_EXIT=0")
  39. list(APPEND ${em_FLAG_LIST_VAR} "-sNODEJS_CATCH_REJECTION=0")
  40. if(DRACO_FAST)
  41. list(APPEND ${em_FLAG_LIST_VAR} "--llvm-lto" "1")
  42. endif()
  43. if(DRACO_WASM)
  44. list(APPEND ${em_FLAG_LIST_VAR} "-sWASM=1")
  45. else()
  46. list(APPEND ${em_FLAG_LIST_VAR} "-sWASM=0")
  47. endif()
  48. if(DRACO_IE_COMPATIBLE)
  49. list(APPEND ${em_FLAG_LIST_VAR} "-sLEGACY_VM_SUPPORT=1")
  50. endif()
  51. endif()
  52. endmacro()
  53. # Macro for generating C++ glue code from IDL for Emscripten targets. Executes
  54. # python to generate the C++ binding, and establishes dendency: $OUTPUT_PATH.cpp
  55. # on $INPUT_IDL.
  56. macro(draco_generate_emscripten_glue)
  57. set(glue_flags)
  58. set(glue_single_arg_opts INPUT_IDL OUTPUT_PATH)
  59. set(glue_multi_arg_opts)
  60. cmake_parse_arguments(glue "${glue_flags}" "${glue_single_arg_opts}"
  61. "${glue_multi_arg_opts}" ${ARGN})
  62. if(DRACO_VERBOSE GREATER 1)
  63. message("--------- draco_generate_emscripten_glue -----------\n"
  64. "glue_INPUT_IDL=${glue_INPUT_IDL}\n"
  65. "glue_OUTPUT_PATH=${glue_OUTPUT_PATH}\n" ]
  66. "----------------------------------------------------\n")
  67. endif()
  68. if(NOT glue_INPUT_IDL OR NOT glue_OUTPUT_PATH)
  69. message(
  70. FATAL_ERROR
  71. "draco_generate_emscripten_glue: INPUT_IDL and OUTPUT_PATH required.")
  72. endif()
  73. # Generate the glue source.
  74. execute_process(COMMAND ${PYTHON_EXECUTABLE}
  75. $ENV{EMSCRIPTEN}/tools/webidl_binder.py
  76. ${glue_INPUT_IDL} ${glue_OUTPUT_PATH})
  77. if(NOT EXISTS "${glue_OUTPUT_PATH}.cpp")
  78. message(FATAL_ERROR "JS glue generation failed for ${glue_INPUT_IDL}.")
  79. endif()
  80. # Create a dependency so that it regenerated on edits.
  81. add_custom_command(OUTPUT "${glue_OUTPUT_PATH}.cpp"
  82. COMMAND ${PYTHON_EXECUTABLE}
  83. $ENV{EMSCRIPTEN}/tools/webidl_binder.py
  84. ${glue_INPUT_IDL} ${glue_OUTPUT_PATH}
  85. DEPENDS ${draco_js_dec_idl}
  86. COMMENT "Generating ${glue_OUTPUT_PATH}.cpp."
  87. WORKING_DIRECTORY ${draco_build}
  88. VERBATIM)
  89. endmacro()
  90. # Wrapper for draco_add_executable() that handles the extra work necessary for
  91. # emscripten targets when generating JS glue:
  92. #
  93. # ~~~
  94. # - Set source level dependency on the C++ binding.
  95. # - Pre/Post link emscripten magic.
  96. #
  97. # Required args:
  98. # - GLUE_PATH: Base path for glue file. Used to generate .cpp and .js files.
  99. # - PRE_LINK_JS_SOURCES: em_link_pre_js() source files.
  100. # - POST_LINK_JS_SOURCES: em_link_post_js() source files.
  101. # Optional args:
  102. # - FEATURES:
  103. # ~~~
  104. macro(draco_add_emscripten_executable)
  105. unset(emexe_NAME)
  106. unset(emexe_FEATURES)
  107. unset(emexe_SOURCES)
  108. unset(emexe_DEFINES)
  109. unset(emexe_INCLUDES)
  110. unset(emexe_LINK_FLAGS)
  111. set(optional_args)
  112. set(single_value_args NAME GLUE_PATH)
  113. set(multi_value_args SOURCES DEFINES FEATURES INCLUDES LINK_FLAGS
  114. PRE_LINK_JS_SOURCES POST_LINK_JS_SOURCES)
  115. cmake_parse_arguments(emexe "${optional_args}" "${single_value_args}"
  116. "${multi_value_args}" ${ARGN})
  117. if(NOT
  118. (emexe_GLUE_PATH
  119. AND emexe_POST_LINK_JS_SOURCES
  120. AND emexe_PRE_LINK_JS_SOURCES))
  121. message(FATAL
  122. "draco_add_emscripten_executable: GLUE_PATH PRE_LINK_JS_SOURCES "
  123. "POST_LINK_JS_SOURCES args required.")
  124. endif()
  125. if(DRACO_VERBOSE GREATER 1)
  126. message("--------- draco_add_emscripten_executable ---------\n"
  127. "emexe_NAME=${emexe_NAME}\n"
  128. "emexe_SOURCES=${emexe_SOURCES}\n"
  129. "emexe_DEFINES=${emexe_DEFINES}\n"
  130. "emexe_INCLUDES=${emexe_INCLUDES}\n"
  131. "emexe_LINK_FLAGS=${emexe_LINK_FLAGS}\n"
  132. "emexe_GLUE_PATH=${emexe_GLUE_PATH}\n"
  133. "emexe_FEATURES=${emexe_FEATURES}\n"
  134. "emexe_PRE_LINK_JS_SOURCES=${emexe_PRE_LINK_JS_SOURCES}\n"
  135. "emexe_POST_LINK_JS_SOURCES=${emexe_POST_LINK_JS_SOURCES}\n"
  136. "----------------------------------------------------\n")
  137. endif()
  138. # The Emscripten linker needs the C++ flags in addition to whatever has been
  139. # passed in with the target.
  140. list(APPEND emexe_LINK_FLAGS ${DRACO_CXX_FLAGS})
  141. if(DRACO_GLTF)
  142. draco_add_executable(NAME
  143. ${emexe_NAME}
  144. OUTPUT_NAME
  145. ${emexe_NAME}_gltf
  146. SOURCES
  147. ${emexe_SOURCES}
  148. DEFINES
  149. ${emexe_DEFINES}
  150. INCLUDES
  151. ${emexe_INCLUDES}
  152. LINK_FLAGS
  153. ${emexe_LINK_FLAGS})
  154. else()
  155. draco_add_executable(NAME ${emexe_NAME} SOURCES ${emexe_SOURCES} DEFINES
  156. ${emexe_DEFINES} INCLUDES ${emexe_INCLUDES} LINK_FLAGS
  157. ${emexe_LINK_FLAGS})
  158. endif()
  159. foreach(feature ${emexe_FEATURES})
  160. draco_enable_feature(FEATURE ${feature} TARGETS ${emexe_NAME})
  161. endforeach()
  162. set_property(SOURCE ${emexe_SOURCES}
  163. APPEND
  164. PROPERTY OBJECT_DEPENDS "${emexe_GLUE_PATH}.cpp")
  165. em_link_pre_js(${emexe_NAME} ${emexe_PRE_LINK_JS_SOURCES})
  166. em_link_post_js(${emexe_NAME} "${emexe_GLUE_PATH}.js"
  167. ${emexe_POST_LINK_JS_SOURCES})
  168. endmacro()