1include(CMakeDependentOption)
4option(MIM_BUILD_LL_RUNTIME
"Compile the ll backend's C runtime wrappers to LLVM IR (requires clang)." ON)
7 "Link the plugins into the binary instead of loading them from shared objects."
8 OFF
"NOT EMSCRIPTEN" ON
11set(MIM_NATIVE_MIM
"" CACHE FILEPATH
"Native mim executable that bootstraps the plugins.")
13set(MIM_PLUGIN_DIR
"${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR}/mim")
14find_program(MIM_CLANG NAMES clang)
15if(MIM_BUILD_LL_RUNTIME AND NOT MIM_CLANG)
17 "MimIR: clang not found; ll backend C runtime wrappers will not be built. "
18 "Set MIM_CLANG or disable MIM_BUILD_LL_RUNTIME to silence this."
25function(mim_transitive_imports mim_file roots out)
26 set(pending
"${mim_file}")
30 list(POP_FRONT pending current)
31 file(READ
"${current}" contents)
32 string(REGEX REPLACE
"/\\*[^*]*\\*+([^/*][^*]*\\*+)*/" "" contents
"${contents}")
33 string(REGEX REPLACE
"//[^\n]*" "" contents
"${contents}")
34 string(REGEX MATCHALL
"(plugin|import)[ \t\r\n]+[A-Za-z0-9_]+" directives
"${contents}")
36 foreach(directive IN LISTS directives)
37 string(REGEX REPLACE
"^(plugin|import)[ \t\r\n]+" "" name
"${directive}")
38 foreach(root IN LISTS roots)
39 set(candidate
"${root}/${name}/${name}.mim")
40 if(EXISTS
"${candidate}")
41 if(NOT candidate IN_LIST files)
42 list(APPEND files
"${candidate}")
43 list(APPEND pending
"${candidate}")
51 set(${out}
"${files}" PARENT_SCOPE)
89function(add_mim_plugin)
92 string(LENGTH
"${PLUGIN}" PLUGIN_LENGTH)
93 if(NOT PLUGIN MATCHES
"^[A-Za-z0-9_]+$" OR PLUGIN_LENGTH GREATER 8)
95 "Mim plugin name '${PLUGIN}' must be 1 to 8 letters, digits, or underscores"
99 cmake_parse_arguments(
107 set(PLUGIN_MIM ${CMAKE_CURRENT_LIST_DIR}/${PLUGIN}.mim)
108 set(OUT_PLUGIN_MIM ${MIM_PLUGIN_DIR}/${PLUGIN}.mim)
109 set(PLUGIN_MD ${CMAKE_BINARY_DIR}/docs/plug/${PLUGIN}.md)
110 set(AUTOGEN_H ${CMAKE_BINARY_DIR}/include/mim/plug/${PLUGIN}/autogen.h)
111 set(AUTOGEN_PY ${CMAKE_BINARY_DIR}/py/mim/_plugins/${PLUGIN}.py)
115 ${CMAKE_BINARY_DIR}/docs/plug/
116 ${CMAKE_BINARY_DIR}/include/mim/plug/${PLUGIN}
117 ${CMAKE_BINARY_DIR}/py/mim/_plugins/
121 set(PLUGIN_ROOTS
"${CMAKE_SOURCE_DIR}/src/mim/plug" "${CMAKE_CURRENT_LIST_DIR}/..")
122 mim_transitive_imports(
"${PLUGIN_MIM}" "${PLUGIN_ROOTS}" PLUGIN_IMPORTS)
125 set(BOOTSTRAP_MIM
"${MIM_NATIVE_MIM}")
126 set(BOOTSTRAP_DEPENDS
"")
127 elseif(MIM_STATIC_PLUGINS)
128 set(BOOTSTRAP_MIM
"$<TARGET_FILE:mim_bootstrap>")
129 set(BOOTSTRAP_DEPENDS
"mim_bootstrap")
131 set(BOOTSTRAP_MIM
"$<TARGET_FILE:${MIM_TARGET_NAMESPACE}mim>")
132 set(BOOTSTRAP_DEPENDS
"${MIM_TARGET_NAMESPACE}mim")
140 COMMAND ${BOOTSTRAP_MIM} ${PLUGIN_MIM} -I
"${CMAKE_SOURCE_DIR}/src/mim/plug" -I
"${CMAKE_CURRENT_LIST_DIR}/.." --bootstrap
141 --output-h ${AUTOGEN_H}
142 --output-md ${PLUGIN_MD}
143 --output-py ${AUTOGEN_PY}
144 MAIN_DEPENDENCY ${PLUGIN_MIM}
145 DEPENDS ${BOOTSTRAP_DEPENDS} ${PLUGIN_IMPORTS}
146 COMMENT
"Bootstrapping MimIR plugin '${PLUGIN_MIM}'"
150 OUTPUT ${OUT_PLUGIN_MIM}
151 COMMAND ${CMAKE_COMMAND} -E copy_if_different ${PLUGIN_MIM} ${OUT_PLUGIN_MIM}
152 DEPENDS ${PLUGIN_MIM}
153 COMMENT
"Copy '${PLUGIN_MIM}' to '${OUT_PLUGIN_MIM}'"
157 add_custom_target(mim_internal_${PLUGIN}
165 if(PLUGIN IN_LIST MIM_PLUGIN_LIST)
166 message(FATAL_ERROR
"Mim plugin '${PLUGIN}' is already registered")
169 list(APPEND MIM_PLUGIN_LIST
"${PLUGIN}")
170 string(APPEND MIM_PLUGIN_LAYOUT
"<tab type=\"user\" url=\"@ref ${PLUGIN}\" title=\"${PLUGIN}\"/>")
172 set(MIM_PLUGIN_LIST
"${MIM_PLUGIN_LIST}" CACHE INTERNAL
"MIM_PLUGIN_LIST")
173 set(MIM_PLUGIN_LAYOUT
"${MIM_PLUGIN_LAYOUT}" CACHE INTERNAL
"MIM_PLUGIN_LAYOUT")
175 if(MIM_STATIC_PLUGINS)
176 add_library(mim_${PLUGIN} STATIC)
178 target_compile_definitions(mim_${PLUGIN} PRIVATE MIM_STATIC_PLUGINS)
180 add_library(mim_${PLUGIN} MODULE)
182 add_dependencies(mim_${PLUGIN} mim_internal_${PLUGIN})
183 target_sources(mim_${PLUGIN}
187 target_include_directories(mim_${PLUGIN}
189 $<BUILD_INTERFACE:${CMAKE_BINARY_DIR}/include>
191 if(EXISTS
"${CMAKE_CURRENT_LIST_DIR}/include")
192 target_include_directories(mim_${PLUGIN}
194 "${CMAKE_CURRENT_LIST_DIR}/include"
197 target_link_libraries(mim_${PLUGIN}
200 ${MIM_TARGET_NAMESPACE}libmim
202 set_target_properties(mim_${PLUGIN}
204 CXX_VISIBILITY_PRESET hidden
205 VISIBILITY_INLINES_HIDDEN 1
206 WINDOWS_EXPORT_ALL_SYMBOLS OFF
209 LIBRARY_OUTPUT_DIRECTORY
"${MIM_PLUGIN_DIR}$<0:>"
216 LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}/mim
217 ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}/mim
218 RUNTIME DESTINATION ${CMAKE_INSTALL_LIBDIR}/mim
219 INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/mim
222 FILES ${OUT_PLUGIN_MIM}
223 DESTINATION ${CMAKE_INSTALL_LIBDIR}/mim
227 DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/mim/plug/${PLUGIN}
229 if(EXISTS
"${CMAKE_CURRENT_LIST_DIR}/include")
231 DIRECTORY
"${CMAKE_CURRENT_LIST_DIR}/include/"
232 DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
247function(mim_static_plugin_registry TARGET)
250 foreach(PLUGIN IN LISTS ARGN)
251 string(APPEND DECLS
"Plugin MIM_PLUGIN_ENTRY_NAME(${PLUGIN})();\n")
252 string(APPEND CALLS
" Driver::add_static_plugin(\"${PLUGIN}\", MIM_PLUGIN_ENTRY_NAME(${PLUGIN}));\n")
255 set(GENERATED ${CMAKE_BINARY_DIR}/src/mim/${TARGET}.cpp)
258 CONTENT
"// Generated by mim_static_plugin_registry; see cmake/Mim.cmake.
275 set(PLUGIN_TARGETS ${ARGN})
276 list(TRANSFORM PLUGIN_TARGETS PREPEND "mim_")
278 add_library(${TARGET} OBJECT ${GENERATED})
279 target_compile_definitions(${TARGET} PRIVATE MIM_STATIC_PLUGINS)
280 target_link_libraries(${TARGET} PUBLIC ${MIM_TARGET_NAMESPACE}libmim ${PLUGIN_TARGETS})
304function(add_mim_runtime)
307 cmake_parse_arguments(
315 if(NOT MIM_BUILD_LL_RUNTIME OR NOT MIM_CLANG)
319 set(RT_DIR ${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR}/mim/rt)
320 file(MAKE_DIRECTORY ${RT_DIR})
321 set(RT_LL ${RT_DIR}/${PLUGIN}_rt.ll)
323 set(RT_SOURCES ${PARSED_SOURCES})
324 list(TRANSFORM RT_SOURCES PREPEND ${CMAKE_CURRENT_LIST_DIR}/)
326 list(LENGTH RT_SOURCES N_SOURCES)
327 if(N_SOURCES EQUAL 1)
330 COMMAND ${MIM_CLANG} -S -emit-llvm -O2 ${PARSED_SOURCES} -o ${RT_LL}
331 DEPENDS ${RT_SOURCES}
332 WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}
333 COMMENT
"Compiling MimIR runtime '${PLUGIN}' to LLVM IR"
337 find_program(MIM_LLVM_LINK NAMES llvm-link)
338 if(NOT MIM_LLVM_LINK)
340 "add_mim_runtime(${PLUGIN}) with multiple SOURCES needs llvm-link to merge them"
344 foreach(src IN LISTS PARSED_SOURCES)
345 cmake_path(GET src STEM stem)
346 set(bc ${RT_DIR}/${PLUGIN}_${stem}.bc)
349 COMMAND ${MIM_CLANG} -emit-llvm -O2 -c ${src} -o ${bc}
350 DEPENDS ${CMAKE_CURRENT_LIST_DIR}/${src}
351 WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}
352 COMMENT
"Compiling MimIR runtime source '${stem}' to LLVM bitcode"
355 list(APPEND RT_BCS ${bc})
359 COMMAND ${MIM_LLVM_LINK} -S ${RT_BCS} -o ${RT_LL}
361 COMMENT
"Linking MimIR runtime '${PLUGIN}' into a single LLVM IR module"
366 add_custom_target(mim_runtime_${PLUGIN} ALL DEPENDS ${RT_LL})
367 if(TARGET mim_${PLUGIN})
368 add_dependencies(mim_${PLUGIN} mim_runtime_${PLUGIN})
372 DESTINATION ${CMAKE_INSTALL_LIBDIR}/mim/rt