AddOCaml.cmake 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  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. explicit_map_components_to_libraries(llvm_libs ${ARG_LLVM})
  60. foreach( llvm_lib ${llvm_libs} )
  61. list(APPEND ocaml_flags "-l${llvm_lib}" )
  62. endforeach()
  63. get_property(system_libs TARGET LLVMSupport PROPERTY LLVM_SYSTEM_LIBS)
  64. foreach(system_lib ${system_libs})
  65. list(APPEND ocaml_flags "-l${system_lib}" )
  66. endforeach()
  67. string(REPLACE ";" " " ARG_CFLAGS "${ARG_CFLAGS}")
  68. set(c_flags "${ARG_CFLAGS} ${LLVM_DEFINITIONS}")
  69. foreach( include_dir ${LLVM_INCLUDE_DIR} ${LLVM_MAIN_INCLUDE_DIR} )
  70. set(c_flags "${c_flags} -I${include_dir}")
  71. endforeach()
  72. foreach( ocaml_file ${ARG_OCAML} )
  73. list(APPEND sources "${ocaml_file}.mli" "${ocaml_file}.ml")
  74. list(APPEND ocaml_inputs "${bin}/${ocaml_file}.mli" "${bin}/${ocaml_file}.ml")
  75. list(APPEND ocaml_outputs "${bin}/${ocaml_file}.cmi" "${bin}/${ocaml_file}.cmo")
  76. if( HAVE_OCAMLOPT )
  77. list(APPEND ocaml_outputs
  78. "${bin}/${ocaml_file}.cmx"
  79. "${bin}/${ocaml_file}${CMAKE_C_OUTPUT_EXTENSION}")
  80. endif()
  81. endforeach()
  82. foreach( c_file ${ARG_C} )
  83. list(APPEND sources "${c_file}.c")
  84. list(APPEND c_inputs "${bin}/${c_file}.c")
  85. list(APPEND c_outputs "${bin}/${c_file}${CMAKE_C_OUTPUT_EXTENSION}")
  86. endforeach()
  87. if( NOT ARG_NOCOPY )
  88. foreach( source ${sources} )
  89. add_custom_command(
  90. OUTPUT "${bin}/${source}"
  91. COMMAND "${CMAKE_COMMAND}" "-E" "copy" "${src}/${source}" "${bin}"
  92. DEPENDS "${src}/${source}"
  93. COMMENT "Copying ${source} to build area")
  94. endforeach()
  95. endif()
  96. foreach( c_input ${c_inputs} )
  97. get_filename_component(basename "${c_input}" NAME_WE)
  98. add_custom_command(
  99. OUTPUT "${basename}${CMAKE_C_OUTPUT_EXTENSION}"
  100. COMMAND "${OCAMLFIND}" "ocamlc" "-c" "${c_input}" -ccopt ${c_flags}
  101. DEPENDS "${c_input}"
  102. COMMENT "Building OCaml stub object file ${basename}${CMAKE_C_OUTPUT_EXTENSION}"
  103. VERBATIM)
  104. endforeach()
  105. set(ocaml_params)
  106. foreach( ocaml_input ${ocaml_inputs} ${c_outputs})
  107. get_filename_component(filename "${ocaml_input}" NAME)
  108. list(APPEND ocaml_params "${filename}")
  109. endforeach()
  110. if( APPLE )
  111. set(ocaml_rpath "@executable_path/../../lib")
  112. elseif( UNIX )
  113. set(ocaml_rpath "\\$ORIGIN/../../lib")
  114. endif()
  115. list(APPEND ocaml_flags "-ldopt" "-Wl,-rpath,${ocaml_rpath}")
  116. add_custom_command(
  117. OUTPUT ${ocaml_outputs}
  118. COMMAND "${OCAMLFIND}" "ocamlmklib" "-o" "${name}" ${ocaml_flags} ${ocaml_params}
  119. DEPENDS ${ocaml_inputs} ${c_outputs}
  120. COMMENT "Building OCaml library ${name}"
  121. VERBATIM)
  122. add_custom_command(
  123. OUTPUT "${bin}/${name}.odoc"
  124. COMMAND "${OCAMLFIND}" "ocamldoc"
  125. "-I" "${bin}"
  126. "-I" "${LLVM_LIBRARY_DIR}/ocaml/"
  127. "-dump" "${bin}/${name}.odoc"
  128. ${ocaml_pkgs} ${ocaml_inputs}
  129. DEPENDS ${ocaml_inputs} ${ocaml_outputs}
  130. COMMENT "Building OCaml documentation for ${name}"
  131. VERBATIM)
  132. add_custom_target("ocaml_${name}" ALL DEPENDS ${ocaml_outputs} "${bin}/${name}.odoc")
  133. set_target_properties("ocaml_${name}" PROPERTIES
  134. OCAML_FLAGS "-I;${bin}")
  135. set_target_properties("ocaml_${name}" PROPERTIES
  136. OCAML_ODOC "${bin}/${name}.odoc")
  137. foreach( ocaml_dep ${ARG_OCAMLDEP} )
  138. add_dependencies("ocaml_${name}" "ocaml_${ocaml_dep}")
  139. endforeach()
  140. foreach( llvm_lib ${llvm_libs} )
  141. add_dependencies("ocaml_${name}" "${llvm_lib}")
  142. endforeach()
  143. set(install_files)
  144. set(install_shlibs)
  145. foreach( ocaml_output ${ocaml_outputs} )
  146. get_filename_component(ext "${ocaml_output}" EXT)
  147. if( NOT (ext STREQUAL ".cmo" OR
  148. ext STREQUAL CMAKE_C_OUTPUT_EXTENSION OR
  149. ext STREQUAL CMAKE_SHARED_LIBRARY_SUFFIX) )
  150. list(APPEND install_files "${ocaml_output}")
  151. elseif( ext STREQUAL CMAKE_SHARED_LIBRARY_SUFFIX)
  152. list(APPEND install_shlibs "${ocaml_output}")
  153. endif()
  154. endforeach()
  155. install(FILES ${install_files}
  156. DESTINATION lib/ocaml)
  157. install(FILES ${install_shlibs}
  158. PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE
  159. GROUP_READ GROUP_EXECUTE
  160. WORLD_READ WORLD_EXECUTE
  161. DESTINATION lib/ocaml)
  162. foreach( install_file ${install_files} ${install_shlibs} )
  163. get_filename_component(filename "${install_file}" NAME)
  164. add_custom_command(TARGET "ocaml_${name}" POST_BUILD
  165. COMMAND "${CMAKE_COMMAND}" "-E" "copy" "${install_file}"
  166. "${LLVM_LIBRARY_DIR}/ocaml/"
  167. COMMENT "Copying OCaml library component ${filename} to intermediate area"
  168. VERBATIM)
  169. endforeach()
  170. endfunction()