AddOCaml.cmake 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  1. # CMake build rules for the OCaml language.
  2. # Assumes FindOCaml is used.
  3. # http://ocaml.org/
  4. #
  5. # Example usage:
  6. #
  7. # add_ocaml_library(pkg_a OCAML mod_a OCAMLDEP pkg_b C mod_a_stubs PKG ctypes LLVM core)
  8. #
  9. # Unnamed parameters:
  10. #
  11. # * Library name.
  12. #
  13. # Named parameters:
  14. #
  15. # OCAML OCaml module names. Imply presence of a corresponding .ml and .mli files.
  16. # OCAMLDEP Names of libraries this library depends on.
  17. # C C stub sources. Imply presence of a corresponding .c file.
  18. # CFLAGS Additional arguments passed when compiling C stubs.
  19. # PKG Names of ocamlfind packages this library depends on.
  20. # LLVM Names of LLVM libraries this library depends on.
  21. # NOCOPY Do not automatically copy sources (.c, .ml, .mli) from the source directory,
  22. # e.g. if they are generated.
  23. #
  24. function(add_ocaml_library name)
  25. CMAKE_PARSE_ARGUMENTS(ARG "NOCOPY" "" "OCAML;OCAMLDEP;C;CFLAGS;PKG;LLVM" ${ARGN})
  26. set(src ${CMAKE_CURRENT_SOURCE_DIR})
  27. set(bin ${CMAKE_CURRENT_BINARY_DIR})
  28. set(ocaml_pkgs)
  29. foreach( ocaml_pkg ${ARG_PKG} )
  30. list(APPEND ocaml_pkgs "-package" "${ocaml_pkg}")
  31. endforeach()
  32. set(sources)
  33. set(ocaml_inputs)
  34. set(ocaml_outputs "${bin}/${name}.cma")
  35. if( ARG_C )
  36. list(APPEND ocaml_outputs
  37. "${bin}/lib${name}${CMAKE_STATIC_LIBRARY_SUFFIX}")
  38. if ( BUILD_SHARED_LIBS )
  39. list(APPEND ocaml_outputs
  40. "${bin}/dll${name}${CMAKE_SHARED_LIBRARY_SUFFIX}")
  41. endif()
  42. endif()
  43. if( HAVE_OCAMLOPT )
  44. list(APPEND ocaml_outputs
  45. "${bin}/${name}.cmxa"
  46. "${bin}/${name}${CMAKE_STATIC_LIBRARY_SUFFIX}")
  47. endif()
  48. set(ocaml_flags "-lstdc++" "-ldopt" "-L${LLVM_LIBRARY_DIR}"
  49. "-ccopt" "-L\\$CAMLORIGIN/../.."
  50. "-ccopt" "-Wl,-rpath,\\$CAMLORIGIN/../.."
  51. ${ocaml_pkgs})
  52. foreach( ocaml_dep ${ARG_OCAMLDEP} )
  53. get_target_property(dep_ocaml_flags "ocaml_${ocaml_dep}" OCAML_FLAGS)
  54. list(APPEND ocaml_flags ${dep_ocaml_flags})
  55. endforeach()
  56. if( NOT BUILD_SHARED_LIBS )
  57. list(APPEND ocaml_flags "-custom")
  58. endif()
  59. if(LLVM_LINK_LLVM_DYLIB)
  60. list(APPEND ocaml_flags "-lLLVM")
  61. else()
  62. explicit_map_components_to_libraries(llvm_libs ${ARG_LLVM})
  63. foreach( llvm_lib ${llvm_libs} )
  64. list(APPEND ocaml_flags "-l${llvm_lib}" )
  65. endforeach()
  66. get_property(system_libs TARGET LLVMSupport PROPERTY LLVM_SYSTEM_LIBS)
  67. foreach(system_lib ${system_libs})
  68. if (system_lib MATCHES "^-")
  69. # If it's an option, pass it without changes.
  70. list(APPEND ocaml_flags "${system_lib}" )
  71. else()
  72. # Otherwise assume it's a library name we need to link with.
  73. list(APPEND ocaml_flags "-l${system_lib}" )
  74. endif()
  75. endforeach()
  76. endif()
  77. string(REPLACE ";" " " ARG_CFLAGS "${ARG_CFLAGS}")
  78. set(c_flags "${ARG_CFLAGS} ${LLVM_DEFINITIONS}")
  79. foreach( include_dir ${LLVM_INCLUDE_DIR} ${LLVM_MAIN_INCLUDE_DIR} )
  80. set(c_flags "${c_flags} -I${include_dir}")
  81. endforeach()
  82. # include -D/-UNDEBUG to match dump function visibility
  83. # regex from HandleLLVMOptions.cmake
  84. string(REGEX MATCH "(^| )[/-][UD] *NDEBUG($| )" flag_matches
  85. "${CMAKE_C_FLAGS_${uppercase_CMAKE_BUILD_TYPE}} ${CMAKE_C_FLAGS}")
  86. set(c_flags "${c_flags} ${flag_matches}")
  87. foreach( ocaml_file ${ARG_OCAML} )
  88. list(APPEND sources "${ocaml_file}.mli" "${ocaml_file}.ml")
  89. list(APPEND ocaml_inputs "${bin}/${ocaml_file}.mli" "${bin}/${ocaml_file}.ml")
  90. list(APPEND ocaml_outputs "${bin}/${ocaml_file}.cmi" "${bin}/${ocaml_file}.cmo")
  91. if( HAVE_OCAMLOPT )
  92. list(APPEND ocaml_outputs
  93. "${bin}/${ocaml_file}.cmx"
  94. "${bin}/${ocaml_file}${CMAKE_C_OUTPUT_EXTENSION}")
  95. endif()
  96. endforeach()
  97. foreach( c_file ${ARG_C} )
  98. list(APPEND sources "${c_file}.c")
  99. list(APPEND c_inputs "${bin}/${c_file}.c")
  100. list(APPEND c_outputs "${bin}/${c_file}${CMAKE_C_OUTPUT_EXTENSION}")
  101. endforeach()
  102. if( NOT ARG_NOCOPY )
  103. foreach( source ${sources} )
  104. add_custom_command(
  105. OUTPUT "${bin}/${source}"
  106. COMMAND "${CMAKE_COMMAND}" "-E" "copy" "${src}/${source}" "${bin}"
  107. DEPENDS "${src}/${source}"
  108. COMMENT "Copying ${source} to build area")
  109. endforeach()
  110. endif()
  111. foreach( c_input ${c_inputs} )
  112. get_filename_component(basename "${c_input}" NAME_WE)
  113. add_custom_command(
  114. OUTPUT "${basename}${CMAKE_C_OUTPUT_EXTENSION}"
  115. COMMAND "${OCAMLFIND}" "ocamlc" "-c" "${c_input}" -ccopt ${c_flags}
  116. DEPENDS "${c_input}"
  117. COMMENT "Building OCaml stub object file ${basename}${CMAKE_C_OUTPUT_EXTENSION}"
  118. VERBATIM)
  119. endforeach()
  120. set(ocaml_params)
  121. foreach( ocaml_input ${ocaml_inputs} ${c_outputs})
  122. get_filename_component(filename "${ocaml_input}" NAME)
  123. list(APPEND ocaml_params "${filename}")
  124. endforeach()
  125. if( APPLE )
  126. set(ocaml_rpath "@executable_path/../../../lib${LLVM_LIBDIR_SUFFIX}")
  127. elseif( UNIX )
  128. set(ocaml_rpath "\\$ORIGIN/../../../lib${LLVM_LIBDIR_SUFFIX}")
  129. endif()
  130. list(APPEND ocaml_flags "-ldopt" "-Wl,-rpath,${ocaml_rpath}")
  131. add_custom_command(
  132. OUTPUT ${ocaml_outputs}
  133. COMMAND "${OCAMLFIND}" "ocamlmklib" "-o" "${name}" ${ocaml_flags} ${ocaml_params}
  134. DEPENDS ${ocaml_inputs} ${c_outputs}
  135. COMMENT "Building OCaml library ${name}"
  136. VERBATIM)
  137. add_custom_command(
  138. OUTPUT "${bin}/${name}.odoc"
  139. COMMAND "${OCAMLFIND}" "ocamldoc"
  140. "-I" "${bin}"
  141. "-I" "${LLVM_LIBRARY_DIR}/ocaml/llvm/"
  142. "-dump" "${bin}/${name}.odoc"
  143. ${ocaml_pkgs} ${ocaml_inputs}
  144. DEPENDS ${ocaml_inputs} ${ocaml_outputs}
  145. COMMENT "Building OCaml documentation for ${name}"
  146. VERBATIM)
  147. add_custom_target("ocaml_${name}" ALL DEPENDS ${ocaml_outputs} "${bin}/${name}.odoc")
  148. set_target_properties("ocaml_${name}" PROPERTIES
  149. OCAML_FLAGS "-I;${bin}")
  150. set_target_properties("ocaml_${name}" PROPERTIES
  151. OCAML_ODOC "${bin}/${name}.odoc")
  152. foreach( ocaml_dep ${ARG_OCAMLDEP} )
  153. add_dependencies("ocaml_${name}" "ocaml_${ocaml_dep}")
  154. endforeach()
  155. if( NOT LLVM_OCAML_OUT_OF_TREE )
  156. foreach( llvm_lib ${llvm_libs} )
  157. add_dependencies("ocaml_${name}" "${llvm_lib}")
  158. endforeach()
  159. endif()
  160. add_dependencies("ocaml_all" "ocaml_${name}")
  161. set(install_files)
  162. set(install_shlibs)
  163. foreach( ocaml_output ${ocaml_inputs} ${ocaml_outputs} )
  164. get_filename_component(ext "${ocaml_output}" EXT)
  165. if( NOT (ext STREQUAL ".cmo" OR
  166. ext STREQUAL ".ml" OR
  167. ext STREQUAL CMAKE_C_OUTPUT_EXTENSION OR
  168. ext STREQUAL CMAKE_SHARED_LIBRARY_SUFFIX) )
  169. list(APPEND install_files "${ocaml_output}")
  170. elseif( ext STREQUAL CMAKE_SHARED_LIBRARY_SUFFIX)
  171. list(APPEND install_shlibs "${ocaml_output}")
  172. endif()
  173. endforeach()
  174. install(FILES ${install_files}
  175. DESTINATION "${LLVM_OCAML_INSTALL_PATH}/llvm")
  176. install(FILES ${install_shlibs}
  177. PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE
  178. GROUP_READ GROUP_EXECUTE
  179. WORLD_READ WORLD_EXECUTE
  180. DESTINATION "${LLVM_OCAML_INSTALL_PATH}/stublibs")
  181. foreach( install_file ${install_files} ${install_shlibs} )
  182. get_filename_component(filename "${install_file}" NAME)
  183. add_custom_command(TARGET "ocaml_${name}" POST_BUILD
  184. COMMAND "${CMAKE_COMMAND}" "-E" "copy" "${install_file}"
  185. "${LLVM_LIBRARY_DIR}/ocaml/llvm/"
  186. COMMENT "Copying OCaml library component ${filename} to intermediate area"
  187. VERBATIM)
  188. add_dependencies("ocaml_${name}" ocaml_make_directory)
  189. endforeach()
  190. endfunction()
  191. add_custom_target(ocaml_make_directory
  192. COMMAND "${CMAKE_COMMAND}" "-E" "make_directory" "${LLVM_LIBRARY_DIR}/ocaml/llvm")
  193. add_custom_target("ocaml_all")
  194. set_target_properties(ocaml_all PROPERTIES FOLDER "Misc")
  195. set_target_properties(ocaml_make_directory PROPERTIES FOLDER "Misc")