plugin-driver.c
1 //! @file plugin-driver.c
2 //! @author J. Marcel van der Veer
3
4 //! @section Copyright
5 //!
6 //! This file is part of Algol68G - an Algol 68 compiler-interpreter.
7 //! Copyright 2001-2025 J. Marcel van der Veer [algol68g@xs4all.nl].
8
9 //! @section License
10 //!
11 //! This program is free software; you can redistribute it and/or modify it
12 //! under the terms of the GNU General Public License as published by the
13 //! Free Software Foundation; either version 3 of the License, or
14 //! (at your option) any later version.
15 //!
16 //! This program is distributed in the hope that it will be useful, but
17 //! WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
18 //! or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
19 //! more details. You should have received a copy of the GNU General Public
20 //! License along with this program. If not, see [http://www.gnu.org/licenses/].
21
22 //! @section Synopsis
23 //!
24 //! Plugin compiler driver.
25
26 #include "a68g.h"
27
28 #include "a68g-optimiser.h"
29 #include "a68g-options.h"
30 #include "a68g-parser.h"
31 #include "a68g-prelude.h"
32 #include "a68g-plugin.h"
33 #include "a68g-genie.h"
34
35 //! @brief Emit code for plugin compiler.
36
37 void plugin_driver_code (void)
38 {
39 if (ERROR_COUNT (&A68G_JOB) == 0 && OPTION_OPT_LEVEL (&A68G_JOB) > NO_OPTIMISE) {
40 announce_phase ("plugin code generator");
41 int num = 0;
42 renumber_nodes (TOP_NODE (&A68G_JOB), &num);
43 A68G (node_register) = (NODE_T **) get_heap_space ((size_t) num * sizeof (NODE_T));
44 ABEND (A68G (node_register) == NO_REF, ERROR_ACTION, NO_TEXT);
45 register_nodes (TOP_NODE (&A68G_JOB));
46 FILE_OBJECT_FD (&A68G_JOB) = open (FILE_OBJECT_NAME (&A68G_JOB), O_WRONLY | O_CREAT | O_TRUNC, A68G_PROTECTION);
47 ABEND (FILE_OBJECT_FD (&A68G_JOB) == A68G_NO_FILE, ERROR_ACTION, FILE_OBJECT_NAME (&A68G_JOB));
48 FILE_OBJECT_OPENED (&A68G_JOB) = A68G_TRUE;
49 plugin_driver_emit (FILE_OBJECT_FD (&A68G_JOB));
50 ASSERT (close (FILE_OBJECT_FD (&A68G_JOB)) == 0);
51 FILE_OBJECT_OPENED (&A68G_JOB) = A68G_FALSE;
52 }
53 }
54
55 //! @brief Compile emitted code.
56
57 void plugin_driver_compile (void)
58 {
59 #if defined (BUILD_A68G_COMPILER)
60 // Compilation on Linux, BSD.
61 // Build shared library using gcc or clang.
62 // TODO: One day this should be all portable between platforms.
63 // Only compile if the A68 compiler found no errors (constant folder for instance).
64 if (ERROR_COUNT (&A68G_JOB) == 0 && OPTION_OPT_LEVEL (&A68G_JOB) > 0 && !OPTION_RUN_SCRIPT (&A68G_JOB)) {
65 BUFFER cmd, options;
66 BUFCLR (cmd);
67 BUFCLR (options);
68 if (OPTION_RERUN (&A68G_JOB) == A68G_FALSE) {
69 announce_phase ("plugin compiler");
70 errno = 0;
71 ASSERT (a68g_bufprt (options, SNPRINTF_SIZE, "%s %s", optimisation_option (), A68G_GCC_OPTIONS) >= 0);
72 #if defined (HAVE_PIC)
73 a68g_bufcat (options, " ", BUFFER_SIZE);
74 a68g_bufcat (options, HAVE_PIC, BUFFER_SIZE);
75 #endif
76
77 // Before Apple Silicon Mac:
78 //
79 // ASSERT (a68g_bufprt (cmd, SNPRINTF_SIZE, "%s -I%s %s -c -o \"%s\" \"%s\"", C_COMPILER, INCLUDE_DIR, options,
80 // FILE_BINARY_NAME (&A68G_JOB), FILE_OBJECT_NAME (&A68G_JOB)) >= 0);
81 // ABEND (system (cmd) != 0, ERROR_ACTION, cmd);
82 // ASSERT (a68g_bufprt (cmd, SNPRINTF_SIZE, "ld -export-dynamic -shared -o \"%s\" \"%s\"",
83 // FILE_PLUGIN_NAME (&A68G_JOB), FILE_BINARY_NAME (&A68G_JOB)) >= 0);
84 // ABEND (system (cmd) != 0, ERROR_ACTION, cmd);
85 //
86 // Apple Silicon Mac patches kindly provided by Neil Matthew.
87
88 ASSERT (a68g_bufprt (cmd, SNPRINTF_SIZE, "%s %s %s -c -o \"%s\" \"%s\"", C_COMPILER, INCLUDE_DIR, options, FILE_BINARY_NAME (&A68G_JOB), FILE_OBJECT_NAME (&A68G_JOB)) >= 0);
89 if (OPTION_VERBOSE (&A68G_JOB)) {
90 ASSERT (a68g_bufprt (A68G (output_line), SNPRINTF_SIZE, "%s: %s", A68G (a68g_cmd_name), cmd) >= 0);
91 io_close_tty_line ();
92 WRITE (A68G_STDOUT, A68G (output_line));
93 }
94 ABEND (system (cmd) != 0, ERROR_ACTION, cmd);
95 ASSERT (a68g_bufprt (cmd, SNPRINTF_SIZE, "ld %s -o \"%s\" \"%s\"", EXPORT_DYNAMIC_FLAGS, FILE_PLUGIN_NAME (&A68G_JOB), FILE_BINARY_NAME (&A68G_JOB)) >= 0);
96 if (OPTION_VERBOSE (&A68G_JOB)) {
97 ASSERT (a68g_bufprt (A68G (output_line), SNPRINTF_SIZE, "%s: %s", A68G (a68g_cmd_name), cmd) >= 0);
98 io_close_tty_line ();
99 WRITE (A68G_STDOUT, A68G (output_line));
100 }
101 ABEND (system (cmd) != 0, ERROR_ACTION, cmd);
102 a68g_rm (FILE_BINARY_NAME (&A68G_JOB));
103 }
104 }
105 #endif
106 }
107
108 //! @brief Start interpreter with compiled plugin.
109
110 void plugin_driver_genie (void)
111 {
112 #if defined (BUILD_A68G_COMPILER)
113 if (OPTION_RUN_SCRIPT (&A68G_JOB)) {
114 rewrite_script_source ();
115 }
116 void *compile_plugin = NULL;
117 if (OPTION_OPT_LEVEL (&A68G_JOB) > 0) {
118 char plugin_name[BUFFER_SIZE];
119 void *a68g_plugin;
120 struct stat srcstat, objstat;
121 int ret;
122 announce_phase ("plugin dynamic linker");
123 ASSERT (a68g_bufprt (plugin_name, SNPRINTF_SIZE, "%s", FILE_PLUGIN_NAME (&A68G_JOB)) >= 0);
124 // Correction when pwd is outside LD_PLUGIN_PATH.
125 // The DL cannot be loaded if it is.
126 if (strcmp (plugin_name, a68g_basename (plugin_name)) == 0) {
127 ASSERT (a68g_bufprt (plugin_name, SNPRINTF_SIZE, "./%s", FILE_PLUGIN_NAME (&A68G_JOB)) >= 0);
128 }
129 // Check whether we are doing something rash.
130 ret = stat (FILE_SOURCE_NAME (&A68G_JOB), &srcstat);
131 ABEND (ret != 0, ERROR_ACTION, FILE_SOURCE_NAME (&A68G_JOB));
132 ret = stat (plugin_name, &objstat);
133 ABEND (ret != 0, ERROR_ACTION, plugin_name);
134 if (OPTION_RERUN (&A68G_JOB)) {
135 ABEND (ST_MTIME (&srcstat) > ST_MTIME (&objstat), "plugin outdates source", "cannot RERUN");
136 }
137 // First load a68g itself so compiler code can resolve a68g symbols.
138 a68g_plugin = dlopen (NULL, RTLD_NOW | RTLD_GLOBAL);
139 ABEND (a68g_plugin == NULL, ERROR_CANNOT_OPEN_PLUGIN, dlerror ());
140 // Then load compiler code.
141 compile_plugin = dlopen (plugin_name, RTLD_NOW | RTLD_GLOBAL);
142 ABEND (compile_plugin == NULL, ERROR_CANNOT_OPEN_PLUGIN, dlerror ());
143 }
144 genie (compile_plugin);
145 // Unload compiler plugin.
146 if (compile_plugin != (void *) NULL) {
147 int ret = dlclose (compile_plugin);
148 ABEND (ret != 0, ERROR_ACTION, dlerror ());
149 }
150 #endif
151 }
152
153 //! @brief Clean files from plugin compiler.
154
155 void plugin_driver_clean (int emitted)
156 {
157 #if defined (BUILD_A68G_COMPILER)
158 announce_phase ("clean up intermediate files");
159 if (OPTION_OPT_LEVEL (&A68G_JOB) >= OPTIMISE_0 && OPTION_REGRESSION_TEST (&A68G_JOB) && !OPTION_KEEP (&A68G_JOB)) {
160 if (emitted) {
161 a68g_rm (FILE_OBJECT_NAME (&A68G_JOB));
162 }
163 a68g_rm (FILE_PLUGIN_NAME (&A68G_JOB));
164 }
165 if (OPTION_RUN_SCRIPT (&A68G_JOB) && !OPTION_KEEP (&A68G_JOB)) {
166 if (emitted) {
167 a68g_rm (FILE_OBJECT_NAME (&A68G_JOB));
168 }
169 a68g_rm (FILE_SOURCE_NAME (&A68G_JOB));
170 a68g_rm (FILE_PLUGIN_NAME (&A68G_JOB));
171 } else if (OPTION_COMPILE (&A68G_JOB)) {
172 build_script ();
173 if (!OPTION_KEEP (&A68G_JOB)) {
174 if (emitted) {
175 a68g_rm (FILE_OBJECT_NAME (&A68G_JOB));
176 }
177 a68g_rm (FILE_PLUGIN_NAME (&A68G_JOB));
178 }
179 } else if (OPTION_OPT_LEVEL (&A68G_JOB) == OPTIMISE_0 && !OPTION_KEEP (&A68G_JOB)) {
180 if (emitted) {
181 a68g_rm (FILE_OBJECT_NAME (&A68G_JOB));
182 }
183 a68g_rm (FILE_PLUGIN_NAME (&A68G_JOB));
184 } else if (OPTION_OPT_LEVEL (&A68G_JOB) > OPTIMISE_0 && !OPTION_KEEP (&A68G_JOB)) {
185 if (emitted) {
186 a68g_rm (FILE_OBJECT_NAME (&A68G_JOB));
187 }
188 } else if (OPTION_RERUN (&A68G_JOB) && !OPTION_KEEP (&A68G_JOB)) {
189 if (emitted) {
190 a68g_rm (FILE_OBJECT_NAME (&A68G_JOB));
191 }
192 }
193 #else
194 (void) emitted;
195 #endif
196 }
© 2002-2025 J.M. van der Veer (jmvdveer@xs4all.nl)
|