Skip to content

Commit 7894921

Browse files
committed
Make dksdk.coder.compile (2/n)
+ Implement compile
1 parent 29b05d4 commit 7894921

File tree

4 files changed

+273
-18
lines changed

4 files changed

+273
-18
lines changed

.ocamlformat

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
version=0.25.1
2+
profile=conventional
3+
exp-grouping=preserve
4+
nested-match=align

.vscode/settings.json

+21-2
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,9 @@
1717
"excludeGlob": [
1818
"**/settings.json",
1919
"**/COPYRIGHT",
20-
"**/LICENSE"
20+
"**/LICENSE",
21+
"**/.ocamlformat",
22+
"**/coder-findlib.conf"
2123
]
2224
},
2325
"psi-header.lang-config": [
@@ -60,6 +62,19 @@
6062
"#!/bin/bash"
6163
]
6264
},
65+
{
66+
"language": "ocaml",
67+
"rootDirFileName": "dk.cmd",
68+
"prefix": " * ",
69+
"suffix": "*",
70+
"begin": "(*************************************************************************",
71+
"end": " *************************************************************************)",
72+
"lineLength": 74
73+
},
74+
{
75+
"language": "ocaml.interface",
76+
"mapTo": "ocaml"
77+
},
6378
{
6479
"language": "yaml",
6580
"mapTo": "cmake"
@@ -91,5 +106,9 @@
91106
""
92107
]
93108
}
94-
]
109+
],
110+
"ocaml.sandbox": {
111+
"kind": "opam",
112+
"switch": "Y:\\source\\dksdk-type"
113+
}
95114
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
destdir="@FINDLIB_DESTDIR@"
2+
path="@FINDLIB_PATH@"

cmake/scripts/dksdk/coder/compile.cmake

+246-16
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ function(help)
2929
set(ARG_MODE FATAL_ERROR)
3030
endif()
3131

32-
cmake_path(APPEND DKSDK_DATA_HOME coder OUTPUT_VARIABLE DKCODER_HOME)
32+
cmake_path(APPEND DKSDK_DATA_HOME coder h OUTPUT_VARIABLE DKCODER_HOME)
3333
cmake_path(NATIVE_PATH DKCODER_HOME DKCODER_HOME_NATIVE)
3434

3535
message(${ARG_MODE} "usage: ./dk dksdk.coder.compile
@@ -43,11 +43,26 @@ downloaded and installed automatically.
4343
Examples
4444
========
4545
46-
./dk dksdk.coder.compile SOURCE expression.ml
47-
Creates `expression.cdi` in the same directory as `expression.ml`
46+
./dk dksdk.coder.compile EXPRESSION Expression.ml
47+
Creates `Expression.cdi` in the same directory as `Expression.ml`.
4848
49-
./dk dksdk.coder.compile SOURCE expression.ml OUTPUT ../compiled.cdi
50-
Creates `../compiled.cdi`
49+
./dk dksdk.coder.compile EXPRESSION Expression.ml OUTPUT ../compiled.cdi
50+
Creates `../compiled.cdi`.
51+
52+
./dk dksdk.coder.compile EXPRESSION Expression.ml MODULES Extra.ml
53+
Creates `Expression.cdi` where `Expression.ml` may use the module
54+
named `Extra` defined by the contents of the file `Extra.ml`.
55+
56+
File Naming
57+
===========
58+
59+
Any `.ml` files must be specified with their first letter capitalized.
60+
On case-sensitive filesystems (Linux, modern NTFS drives on Windows, but
61+
not macOS and older FAT/FAT32 Windows drives) that means the `.ml`
62+
files must be capitalized.
63+
64+
So name and refer to your files as `Expression.ml` (etc.) not
65+
`expression.ml` (etc.).
5166
5267
Arguments
5368
=========
@@ -58,8 +73,35 @@ HELP
5873
QUIET
5974
Do not print CMake STATUS messages.
6075
61-
SOURCE filename
62-
The name of the file containing Coder expressions.
76+
EXPRESSION filename
77+
The path of the file containing Coder expressions. The path may
78+
start with a tilde (~) which will be treated as the home
79+
directory on Unix or the USERPROFILE directory on Windows.
80+
81+
The file MUST contain the `module E` and the `blocks` field at
82+
minimum:
83+
84+
open DkSDKCoder_Std
85+
module E (I : Cdinst.Lang.SYM) = struct
86+
let blocks = []
87+
end
88+
89+
That absolute minimum will not generate any source code. A more
90+
realistic minimum is the following:
91+
92+
open DkSDKCoder_Std
93+
module E (I : Cdinst.Lang.SYM) = struct
94+
open I
95+
let blocks = [
96+
block
97+
(label ~project:\"p\" ~deployment:\"d\" \"somename\" [])
98+
[declare (typeregister \"Hi\") unit]
99+
noop
100+
]
101+
end
102+
103+
MODULES module_filenames
104+
Optional list of module filenames that can be used by the EXPRESSION.
63105
64106
OUTPUT filename
65107
The name of the output CDI file.
@@ -71,23 +113,157 @@ NO_SYSTEM_PATH
71113
72114
VERSION version
73115
Use the version specified rather than the built-in ${DKCODER_COMPILE_VERSION}
74-
dkcoder version. CAUTION: Using this option causes the SHA-256 integrity checks
75-
to be skipped.
116+
dkcoder version.
117+
118+
CAUTION: Using this option causes the SHA-256 integrity checks to be skipped.
119+
120+
CAUTION: If the version is a branch rather than a specific version number,
121+
there is no way for `dksdk.coder.compile` to know about branch updates. The
122+
branch version will never be updated once downloaded initially. You will need
123+
to delete the branch at `${DKCODER_HOME_NATIVE}` manually to overcome this
124+
limitation.
125+
126+
Optimizations
127+
=============
128+
129+
1. The first time you run `dksdk.coder.compile` will download and install DkSDK
130+
Coder cached on the [VERSION]. Subsequent times will not redownload nor
131+
reinstall DkSDK Coder unless the [VERSION] is different.
132+
2. A compilation directory will be created and cached based on the absolute
133+
path to the [EXPRESSION filename] and any [MODULES filenames]. That means first time
134+
compilations for a EXPRESSION and MODULES may take a few seconds, but subsequent
135+
compiles should be quick (assuming the EXPRESSION and MODULES are not terribly
136+
complicated).
76137
")
77138
endfunction()
78139

140+
function(dkcoder_compile)
141+
set(noValues)
142+
set(singleValues EXPRESSION_PATH OUTPUT)
143+
set(multiValues EXTRA_MODULE_PATHS)
144+
cmake_parse_arguments(PARSE_ARGV 0 ARG "${noValues}" "${singleValues}" "${multiValues}")
145+
146+
# Make absolute path to EXPRESSION, including expanding tilde (~)
147+
file(REAL_PATH "${ARG_EXPRESSION_PATH}" expression_abspath EXPAND_TILDE)
148+
dkcoder_get_validated_module_name(${expression_abspath})
149+
150+
# EXPRESSION and EXECUTABLE_NAME is for dune.tmpl and to name a generated file below
151+
set(EXPRESSION "${MODULE_NAME}")
152+
set(main_module "${EXPRESSION}Main")
153+
set(EXECUTABLE_NAME "${main_module}")
154+
155+
# Convert EXTRA_MODULE_PATHS to absolute paths
156+
set(all_modules "${EXPRESSION}" "${main_module}")
157+
set(extra_module_paths)
158+
foreach(extra_module_path IN LISTS ARG_EXTRA_MODULE_PATHS)
159+
file(REAL_PATH "${extra_module_path}" m_abspath EXPAND_TILDE)
160+
dkcoder_get_validated_module_name(${m_abspath})
161+
list(APPEND all_modules "${MODULE_NAME}")
162+
list(APPEND extra_module_paths "${m_abspath}")
163+
endforeach()
164+
165+
# MODULES is for dune.tmpl
166+
list(JOIN all_modules " " MODULES)
167+
168+
# Read the footer
169+
file(READ "${DKCODER_ETC}/Main.ml.tmpl" FOOTER_CONTENTS)
170+
171+
# Hash (which normalizes first) to make a compilation identifier
172+
cmake_path(HASH expression_abspath pathhash)
173+
set(compile_id_inputs ${pathhash})
174+
foreach(extra_module_path IN LISTS extra_module_paths)
175+
cmake_path(HASH extra_module_path pathhash)
176+
list(APPEND compile_id_inputs ${pathhash})
177+
endforeach()
178+
string(SHA256 COMPILE_ID "${compile_id_inputs}")
179+
string(SUBSTRING "${COMPILE_ID}" 0 8 COMPILE_ID)
180+
181+
# Compile directory
182+
cmake_path(APPEND DKSDK_DATA_HOME coder c ${COMPILE_ID} OUTPUT_VARIABLE compile_dir)
183+
file(MAKE_DIRECTORY "${compile_dir}")
184+
185+
# Place template files into compile directory
186+
file(COPY_FILE "${DKCODER_ETC}/dune-project.tmpl" "${compile_dir}/dune-project" ONLY_IF_DIFFERENT)
187+
# Uses @EXECUTABLE_NAME@ and @MODULES@
188+
configure_file("${DKCODER_ETC}/dune.tmpl" "${compile_dir}/dune" @ONLY)
189+
# Uses @EXPRESSION@
190+
configure_file("${DKCODER_ETC}/Main.ml.tmpl" "${compile_dir}/${main_module}.ml" @ONLY)
191+
# The expression file itself.
192+
file(CREATE_LINK "${expression_abspath}" "${compile_dir}/${EXPRESSION}.ml" COPY_ON_ERROR SYMBOLIC)
193+
# And extra modules
194+
foreach(extra_module_path IN LISTS extra_module_paths)
195+
cmake_path(GET extra_module_path FILENAME m_filename)
196+
file(CREATE_LINK "${extra_module_path}" "${compile_dir}/${m_filename}" COPY_ON_ERROR SYMBOLIC)
197+
endforeach()
198+
199+
# Make a findlib.conf
200+
set(FINDLIB_PATH "${DKCODER_LIB}")
201+
set(FINDLIB_DESTDIR "${DKCODER_LIB}")
202+
if(CMAKE_HOST_WIN32)
203+
cmake_path(NATIVE_PATH FINDLIB_PATH FINDLIB_PATH)
204+
cmake_path(NATIVE_PATH FINDLIB_DESTDIR FINDLIB_DESTDIR)
205+
# Escape backslashes
206+
string(REPLACE "\\" "\\\\" FINDLIB_PATH "${FINDLIB_PATH}")
207+
string(REPLACE "\\" "\\\\" FINDLIB_DESTDIR "${FINDLIB_DESTDIR}")
208+
endif()
209+
configure_file("${CMAKE_CURRENT_FUNCTION_LIST_DIR}/../../__dk-tmpl/coder-findlib.conf" "${compile_dir}/findlib.conf" @ONLY)
210+
211+
# Build the bytecode executable
212+
execute_process(
213+
COMMAND
214+
215+
# Environment variables tested at dksdk-coder/ci/test-std-helper-dunebuild.sh
216+
"${CMAKE_COMMAND}" -E env
217+
"OCAMLLIB=${DKCODER_LIB}/ocaml"
218+
"OCAMLFIND_CONF=${compile_dir}/findlib.conf"
219+
"CAML_LD_LIBRARY_PATH=${DKCODER_LIB}/ocaml/stublibs"
220+
--modify "PATH=path_list_prepend:${DKCODER_LIB}/ocaml/stublibs"
221+
--modify "PATH=path_list_prepend:${DKCODER_BIN}"
222+
--
223+
224+
"${DKCODER_DUNE}" build
225+
--root "${compile_dir}"
226+
--display=short
227+
--no-buffer
228+
--no-print-directory
229+
--no-config
230+
"${EXECUTABLE_NAME}.bc"
231+
COMMAND_ERROR_IS_FATAL ANY
232+
)
233+
234+
# Execute bytecode executable
235+
execute_process(
236+
COMMAND
237+
238+
# Environment variables tested at dksdk-coder/ci/test-std-helper-dunebuild.sh
239+
"${CMAKE_COMMAND}" -E env
240+
"CAML_LD_LIBRARY_PATH=${DKCODER_LIB}/ocaml/stublibs:${DKCODER_LIB}/stublibs"
241+
--modify "PATH=path_list_prepend:${DKCODER_LIB}/stublibs"
242+
--modify "PATH=path_list_prepend:${DKCODER_LIB}/ocaml/stublibs"
243+
--
244+
245+
"${DKCODER_OCAMLRUN}" "${compile_dir}/_build/default/${EXECUTABLE_NAME}.bc" "${ARG_OUTPUT}"
246+
COMMAND_ERROR_IS_FATAL ANY
247+
)
248+
endfunction()
249+
79250
# Outputs:
80251
# - DKCODER - location of dkcoder executable
252+
# - DKCODER_BIN - location of bin directory
253+
# - DKCODER_ETC - location of etc/dkcoder directory
254+
# - DKCODER_LIB - location of lib/ directory containing lib/ocaml/ and other libraries compatible with dkcoder
81255
# - DKCODER_OCAMLC - location of ocamlc compatible with dkcoder
82256
# - DKCODER_OCAMLRUN - location of ocamlrun compatible with dkcoder
83257
# - DKCODER_DUNE - location of dune compatible with dkcoder
84-
function(install_dkcoder)
258+
function(dkcoder_install)
85259
set(noValues NO_SYSTEM_PATH ENFORCE_SHA256)
86260
set(singleValues VERSION)
87261
set(multiValues)
88262
cmake_parse_arguments(PARSE_ARGV 0 ARG "${noValues}" "${singleValues}" "${multiValues}")
89263

90-
cmake_path(APPEND DKSDK_DATA_HOME coder OUTPUT_VARIABLE DKCODER_HOME)
264+
# Make a DkSDK Coder home
265+
cmake_path(APPEND DKSDK_DATA_HOME coder h ${ARG_VERSION} OUTPUT_VARIABLE DKCODER_HOME)
266+
91267
set(hints ${DKCODER_HOME}/bin)
92268
set(find_program_INITIAL)
93269
if(ARG_NO_SYSTEM_PATH)
@@ -170,11 +346,50 @@ function(install_dkcoder)
170346
find_program(DKCODER NAMES dkcoder REQUIRED HINTS ${hints})
171347
endif()
172348

173-
# ocamlc, ocamlrun and dune must be in the same directory as dkcoder.
174349
cmake_path(GET DKCODER PARENT_PATH dkcoder_bindir)
350+
cmake_path(GET dkcoder_bindir PARENT_PATH dkcoder_rootdir)
351+
352+
# ocamlc, ocamlrun and dune must be in the same directory as dkcoder.
175353
find_program(DKCODER_OCAMLC NAMES ocamlc REQUIRED NO_DEFAULT_PATH HINTS ${dkcoder_bindir})
176354
find_program(DKCODER_OCAMLRUN NAMES ocamlrun REQUIRED NO_DEFAULT_PATH HINTS ${dkcoder_bindir})
177355
find_program(DKCODER_DUNE NAMES dune REQUIRED NO_DEFAULT_PATH HINTS ${dkcoder_bindir})
356+
357+
# bin
358+
cmake_path(APPEND dkcoder_rootdir bin OUTPUT_VARIABLE dkcoder_bin)
359+
if(NOT IS_DIRECTORY "${dkcoder_bin}")
360+
message(FATAL_ERROR "Expected ${dkcoder_bin} to be present")
361+
endif()
362+
set(DKCODER_BIN "${dkcoder_bin}" PARENT_SCOPE)
363+
364+
# etc/dkcoder
365+
cmake_path(APPEND dkcoder_rootdir etc dkcoder OUTPUT_VARIABLE dkcoder_etc)
366+
if(NOT IS_DIRECTORY "${dkcoder_etc}")
367+
message(FATAL_ERROR "Expected ${dkcoder_etc} to be present")
368+
endif()
369+
set(DKCODER_ETC "${dkcoder_etc}" PARENT_SCOPE)
370+
371+
# lib
372+
cmake_path(APPEND dkcoder_rootdir lib OUTPUT_VARIABLE dkcoder_lib)
373+
if(NOT IS_DIRECTORY "${dkcoder_lib}")
374+
message(FATAL_ERROR "Expected ${dkcoder_lib} to be present")
375+
endif()
376+
set(DKCODER_LIB "${dkcoder_lib}" PARENT_SCOPE)
377+
endfunction()
378+
379+
# Output - MODULE_NAME
380+
function(dkcoder_get_validated_module_name path)
381+
if(path STREQUAL "")
382+
message(FATAL_ERROR "The path to the module is required.")
383+
endif()
384+
cmake_path(GET path FILENAME name)
385+
string(TOUPPER "${name}" name_upper)
386+
string(SUBSTRING "${name}" 0 1 first_char)
387+
string(SUBSTRING "${name_upper}" 0 1 first_char_upper)
388+
if(NOT first_char STREQUAL first_char_upper)
389+
message(FATAL_ERROR "The name of a module must start with a capital letter. Instead '${name}' was used.")
390+
endif()
391+
cmake_path(REMOVE_EXTENSION name OUTPUT_VARIABLE module_name)
392+
set(MODULE_NAME "${module_name}" PARENT_SCOPE)
178393
endfunction()
179394

180395
function(run)
@@ -184,8 +399,8 @@ function(run)
184399
set(CMAKE_CURRENT_BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CURRENT_FUNCTION}")
185400

186401
set(noValues HELP QUIET NO_SYSTEM_PATH)
187-
set(singleValues VERSION)
188-
set(multiValues)
402+
set(singleValues VERSION EXPRESSION OUTPUT)
403+
set(multiValues MODULES)
189404
cmake_parse_arguments(PARSE_ARGV 0 ARG "${noValues}" "${singleValues}" "${multiValues}")
190405

191406
if(ARG_HELP)
@@ -209,12 +424,27 @@ function(run)
209424
# VERSION
210425
if(ARG_VERSION)
211426
set(VERSION ${ARG_VERSION})
212-
set(expand_ENFORCE_SHA256)
427+
set(expand_ENFORCE_SHA256)
213428
else()
214429
set(VERSION ${DKCODER_COMPILE_VERSION})
215430
set(expand_ENFORCE_SHA256 ENFORCE_SHA256)
216431
endif()
217432

218-
install_dkcoder(VERSION ${VERSION} ${expand_NO_SYSTEM_PATH} ${expand_ENFORCE_SHA256})
433+
# EXPRESSION
434+
if(NOT ARG_EXPRESSION)
435+
help(MODE NOTICE)
436+
message(NOTICE "Missing EXPRESSION argument")
437+
return()
438+
endif()
439+
440+
# OUTPUT
441+
if(ARG_OUTPUT)
442+
set(OUTPUT ${ARG_OUTPUT})
443+
else()
444+
cmake_path(REPLACE_EXTENSION ARG_EXPRESSION LAST_ONLY .cdi OUTPUT_VARIABLE OUTPUT)
445+
endif()
446+
447+
dkcoder_install(VERSION ${VERSION} ${expand_NO_SYSTEM_PATH} ${expand_ENFORCE_SHA256})
219448
message(STATUS "dkcoder is at: ${DKCODER}")
449+
dkcoder_compile(EXPRESSION_PATH ${ARG_EXPRESSION} EXTRA_MODULE_PATHS ${ARG_MODULES} OUTPUT ${OUTPUT})
220450
endfunction()

0 commit comments

Comments
 (0)