aboutsummaryrefslogtreecommitdiff
path: root/rcc/cmake/modules/AddOCaml.cmake
diff options
context:
space:
mode:
authorRichard Qin <richard.qin.x@gmail.com>2026-10-21 08:10:34 +0800
committerRichard Qin <richard.qin.x@gmail.com>2026-10-21 08:10:34 +0800
commitbbfffc8ce49b9afe854f0799513ab6b7891d6dab (patch)
treed1b2a1cc8166270764b627960fa193b60e9b3271 /rcc/cmake/modules/AddOCaml.cmake
parent49de843452f161ee42cb8f4ff4780ccc02ae3a7a (diff)
downloadrcc-project-bbfffc8ce49b9afe854f0799513ab6b7891d6dab.tar.gz
rcc-project-bbfffc8ce49b9afe854f0799513ab6b7891d6dab.tar.xz
[CMake] Add RCC platform configuration checks
Diffstat (limited to 'rcc/cmake/modules/AddOCaml.cmake')
-rw-r--r--rcc/cmake/modules/AddOCaml.cmake239
1 files changed, 239 insertions, 0 deletions
diff --git a/rcc/cmake/modules/AddOCaml.cmake b/rcc/cmake/modules/AddOCaml.cmake
new file mode 100644
index 0000000..01fb5a1
--- /dev/null
+++ b/rcc/cmake/modules/AddOCaml.cmake
@@ -0,0 +1,239 @@
+# CMake build rules for the OCaml language.
+# Assumes FindOCaml is used.
+# http://ocaml.org/
+#
+# Example usage:
+#
+# add_ocaml_library(pkg_a OCAML mod_a OCAMLDEP pkg_b C mod_a_stubs PKG ctypes RCC core)
+#
+# Unnamed parameters:
+#
+# * Library name.
+#
+# Named parameters:
+#
+# OCAML OCaml module names. Imply presence of a corresponding .ml and .mli files.
+# OCAMLDEP Names of libraries this library depends on.
+# C C stub sources. Imply presence of a corresponding .c file.
+# CFLAGS Additional arguments passed when compiling C stubs.
+# PKG Names of ocamlfind packages this library depends on.
+# RCC Names of RCC libraries this library depends on.
+# NOCOPY Do not automatically copy sources (.c, .ml, .mli) from the source directory,
+# e.g. if they are generated.
+#
+
+function(add_ocaml_library name)
+ CMAKE_PARSE_ARGUMENTS(ARG "NOCOPY" "" "OCAML;OCAMLDEP;C;CFLAGS;PKG;RCC" ${ARGN})
+
+ set(src ${CMAKE_CURRENT_SOURCE_DIR})
+ set(bin ${CMAKE_CURRENT_BINARY_DIR})
+
+ set(ocaml_pkgs)
+ foreach( ocaml_pkg ${ARG_PKG} )
+ list(APPEND ocaml_pkgs "-package" "${ocaml_pkg}")
+ endforeach()
+
+ set(sources)
+
+ set(ocaml_inputs)
+
+ set(ocaml_outputs "${bin}/${name}.cma")
+ if( ARG_C )
+ list(APPEND ocaml_outputs
+ "${bin}/lib${name}${CMAKE_STATIC_LIBRARY_SUFFIX}")
+ if ( BUILD_SHARED_LIBS )
+ list(APPEND ocaml_outputs
+ "${bin}/dll${name}${CMAKE_SHARED_LIBRARY_SUFFIX}")
+ endif()
+ endif()
+ if( HAVE_OCAMLOPT )
+ list(APPEND ocaml_outputs
+ "${bin}/${name}.cmxa"
+ "${bin}/${name}${CMAKE_STATIC_LIBRARY_SUFFIX}")
+ endif()
+
+ set(ocaml_flags "-lstdc++" "-ldopt" "-L${RCC_LIBRARY_DIR}"
+ "-ccopt" "-L\\$CAMLORIGIN/../.."
+ "-ccopt" "-Wl,-rpath,\\$CAMLORIGIN/../.."
+ ${ocaml_pkgs})
+
+ set(ocaml_dep_inputs)
+ foreach( ocaml_dep ${ARG_OCAMLDEP} )
+ get_target_property(dep_ocaml_flags "ocaml_${ocaml_dep}" OCAML_FLAGS)
+ list(APPEND ocaml_flags ${dep_ocaml_flags})
+ get_target_property(dep_ocaml_outputs "ocaml_${ocaml_dep}" OCAML_OUTPUTS)
+ list(APPEND ocaml_dep_inputs ${dep_ocaml_outputs})
+ endforeach()
+
+ if( NOT BUILD_SHARED_LIBS )
+ list(APPEND ocaml_flags "-custom")
+ endif()
+
+ if(RCC_LINK_RCC_DYLIB)
+ list(APPEND ocaml_flags "-lRCC")
+ else()
+ explicit_map_components_to_libraries(rcc_libs ${ARG_RCC})
+ foreach( rcc_lib ${rcc_libs} )
+ list(APPEND ocaml_flags "-l${rcc_lib}" )
+ endforeach()
+
+ get_property(system_libs TARGET RCCSupport PROPERTY RCC_SYSTEM_LIBS)
+ foreach(system_lib ${system_libs})
+ if (system_lib MATCHES "^-")
+ # If it's an option, pass it without changes.
+ list(APPEND ocaml_flags "${system_lib}" )
+ else()
+ # Otherwise assume it's a library name we need to link with.
+ list(APPEND ocaml_flags "-l${system_lib}" )
+ endif()
+ endforeach()
+ endif()
+
+ string(REPLACE ";" " " ARG_CFLAGS "${ARG_CFLAGS}")
+ set(c_flags "${ARG_CFLAGS} ${RCC_DEFINITIONS}")
+ foreach( include_dir ${RCC_INCLUDE_DIR} ${RCC_MAIN_INCLUDE_DIR} )
+ set(c_flags "${c_flags} -I${include_dir}")
+ endforeach()
+ # include -D/-UNDEBUG to match dump function visibility
+ # regex from HandleRCCOptions.cmake
+ string(REGEX MATCH "(^| )[/-][UD] *NDEBUG($| )" flag_matches
+ "${CMAKE_C_FLAGS_${uppercase_CMAKE_BUILD_TYPE}} ${CMAKE_C_FLAGS}")
+ set(c_flags "${c_flags} ${flag_matches}")
+
+ foreach( ocaml_file ${ARG_OCAML} )
+ list(APPEND sources "${ocaml_file}.mli" "${ocaml_file}.ml")
+
+ list(APPEND ocaml_inputs "${bin}/${ocaml_file}.mli" "${bin}/${ocaml_file}.ml")
+
+ list(APPEND ocaml_outputs "${bin}/${ocaml_file}.cmi" "${bin}/${ocaml_file}.cmo")
+
+ list(APPEND ocaml_outputs "${bin}/${ocaml_file}.cmti" "${bin}/${ocaml_file}.cmt")
+
+ if( HAVE_OCAMLOPT )
+ list(APPEND ocaml_outputs
+ "${bin}/${ocaml_file}.cmx"
+ "${bin}/${ocaml_file}${CMAKE_C_OUTPUT_EXTENSION}")
+ endif()
+ endforeach()
+
+ foreach( c_file ${ARG_C} )
+ list(APPEND sources "${c_file}.c")
+
+ list(APPEND c_inputs "${bin}/${c_file}.c")
+ list(APPEND c_outputs "${bin}/${c_file}${CMAKE_C_OUTPUT_EXTENSION}")
+ endforeach()
+
+ if( NOT ARG_NOCOPY )
+ foreach( source ${sources} )
+ add_custom_command(
+ OUTPUT "${bin}/${source}"
+ COMMAND "${CMAKE_COMMAND}" "-E" "copy" "${src}/${source}" "${bin}"
+ DEPENDS "${src}/${source}"
+ COMMENT "Copying ${source} to build area")
+ endforeach()
+ endif()
+
+ foreach( c_input ${c_inputs} )
+ get_filename_component(basename "${c_input}" NAME_WE)
+ add_custom_command(
+ OUTPUT "${basename}${CMAKE_C_OUTPUT_EXTENSION}"
+ COMMAND "${OCAMLFIND}" "ocamlc" "-c" "${c_input}" -ccopt ${c_flags}
+ DEPENDS "${c_input}"
+ COMMENT "Building OCaml stub object file ${basename}${CMAKE_C_OUTPUT_EXTENSION}"
+ VERBATIM)
+ endforeach()
+
+ set(ocaml_params)
+ foreach( ocaml_input ${ocaml_inputs} ${c_outputs})
+ get_filename_component(filename "${ocaml_input}" NAME)
+ list(APPEND ocaml_params "${filename}")
+ endforeach()
+
+ if( APPLE )
+ set(ocaml_rpath "@executable_path/../../../lib${RCC_LIBDIR_SUFFIX}")
+ elseif( UNIX )
+ set(ocaml_rpath "\\$ORIGIN/../../../lib${RCC_LIBDIR_SUFFIX}")
+ endif()
+ list(APPEND ocaml_flags "-ldopt" "-Wl,-rpath,${ocaml_rpath}")
+
+ add_custom_command(
+ OUTPUT ${ocaml_outputs}
+ COMMAND "${OCAMLFIND}" "ocamlmklib" "-ocamlcflags" "-bin-annot"
+ "-o" "${name}" ${ocaml_flags} ${ocaml_params}
+ DEPENDS ${ocaml_inputs} ${ocaml_dep_inputs} ${c_outputs}
+ COMMENT "Building OCaml library ${name}"
+ VERBATIM)
+
+ add_custom_command(
+ OUTPUT "${bin}/${name}.odoc"
+ COMMAND "${OCAMLFIND}" "ocamldoc"
+ "-I" "${bin}"
+ "-I" "${RCC_LIBRARY_DIR}/ocaml/rcc/"
+ "-dump" "${bin}/${name}.odoc"
+ ${ocaml_pkgs} ${ocaml_inputs}
+ DEPENDS ${ocaml_inputs} ${ocaml_dep_inputs} ${ocaml_outputs}
+ COMMENT "Building OCaml documentation for ${name}"
+ VERBATIM)
+
+ add_custom_target("ocaml_${name}" ALL DEPENDS ${ocaml_outputs} "${bin}/${name}.odoc")
+ get_subproject_title(subproject_title)
+ set_target_properties("ocaml_${name}" PROPERTIES FOLDER "${subproject_title}/Bindings/OCaml")
+
+ set_target_properties("ocaml_${name}" PROPERTIES
+ OCAML_FLAGS "-I;${bin}")
+ set_target_properties("ocaml_${name}" PROPERTIES
+ OCAML_ODOC "${bin}/${name}.odoc")
+ set_target_properties("ocaml_${name}" PROPERTIES
+ OCAML_OUTPUTS "${ocaml_outputs}")
+
+ foreach( ocaml_dep ${ARG_OCAMLDEP} )
+ add_dependencies("ocaml_${name}" "ocaml_${ocaml_dep}")
+ endforeach()
+
+ if( NOT RCC_OCAML_OUT_OF_TREE )
+ foreach( rcc_lib ${rcc_libs} )
+ add_dependencies("ocaml_${name}" "${rcc_lib}")
+ endforeach()
+ endif()
+
+ add_dependencies("ocaml_all" "ocaml_${name}")
+
+ set(install_files)
+ set(install_shlibs)
+ foreach( ocaml_output ${ocaml_inputs} ${ocaml_outputs} )
+ get_filename_component(ext "${ocaml_output}" EXT)
+
+ if( NOT (ext STREQUAL ".cmo" OR
+ ext STREQUAL ".ml" OR
+ ext STREQUAL CMAKE_C_OUTPUT_EXTENSION OR
+ ext STREQUAL CMAKE_SHARED_LIBRARY_SUFFIX) )
+ list(APPEND install_files "${ocaml_output}")
+ elseif( ext STREQUAL CMAKE_SHARED_LIBRARY_SUFFIX)
+ list(APPEND install_shlibs "${ocaml_output}")
+ endif()
+ endforeach()
+
+ install(FILES ${install_files}
+ DESTINATION "${RCC_OCAML_INSTALL_PATH}/rcc")
+ install(FILES ${install_shlibs}
+ PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE
+ GROUP_READ GROUP_EXECUTE
+ WORLD_READ WORLD_EXECUTE
+ DESTINATION "${RCC_OCAML_INSTALL_PATH}/stublibs")
+
+ foreach( install_file ${install_files} ${install_shlibs} )
+ get_filename_component(filename "${install_file}" NAME)
+ add_custom_command(TARGET "ocaml_${name}" POST_BUILD
+ COMMAND "${CMAKE_COMMAND}" "-E" "copy" "${install_file}"
+ "${RCC_LIBRARY_DIR}/ocaml/rcc/"
+ COMMENT "Copying OCaml library component ${filename} to intermediate area"
+ VERBATIM)
+ add_dependencies("ocaml_${name}" ocaml_make_directory)
+ endforeach()
+endfunction()
+
+add_custom_target(ocaml_make_directory
+ COMMAND "${CMAKE_COMMAND}" "-E" "make_directory" "${RCC_LIBRARY_DIR}/ocaml/rcc")
+add_custom_target("ocaml_all")
+set_target_properties(ocaml_all PROPERTIES FOLDER "RCC/Bindings/OCaml")
+set_target_properties(ocaml_make_directory PROPERTIES FOLDER "RCC/Bindings/OCaml")