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-2024 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-plugin.h"
32 #include "a68g-genie.h"
33
34 //! @brief Emit code for plugin compiler.
35
36 void plugin_driver_code (void)
37 {
38 if (ERROR_COUNT (&A68_JOB) == 0 && OPTION_OPT_LEVEL (&A68_JOB) > NO_OPTIMISE) {
39 announce_phase ("plugin code generator");
40 int num = 0;
41 renumber_nodes (TOP_NODE (&A68_JOB), &num);
42 A68 (node_register) = (NODE_T **) get_heap_space ((size_t) num * sizeof (NODE_T));
43 ABEND (A68 (node_register) == NO_VAR, ERROR_ACTION, __func__);
44 register_nodes (TOP_NODE (&A68_JOB));
45 FILE_OBJECT_FD (&A68_JOB) = open (FILE_OBJECT_NAME (&A68_JOB), O_WRONLY | O_CREAT | O_TRUNC, A68_PROTECTION);
46 ABEND (FILE_OBJECT_FD (&A68_JOB) == -1, ERROR_ACTION, FILE_OBJECT_NAME (&A68_JOB));
47 FILE_OBJECT_OPENED (&A68_JOB) = A68_TRUE;
48 plugin_driver_emit (FILE_OBJECT_FD (&A68_JOB));
49 ASSERT (close (FILE_OBJECT_FD (&A68_JOB)) == 0);
50 FILE_OBJECT_OPENED (&A68_JOB) = A68_FALSE;
51 }
52 }
53
54 //! @brief Compile emitted code.
55
56 void plugin_driver_compile (void)
57 {
58 #if defined (BUILD_A68_COMPILER)
59 // Compilation on Linux, BSD.
60 // Build shared library using gcc or clang.
61 // TODO: One day this should be all portable between platforms.
62 // Only compile if the A68 compiler found no errors (constant folder for instance).
63 if (ERROR_COUNT (&A68_JOB) == 0 && OPTION_OPT_LEVEL (&A68_JOB) > 0 && !OPTION_RUN_SCRIPT (&A68_JOB)) {
64 BUFFER cmd, options;
65 BUFCLR (cmd);
66 BUFCLR (options);
67 if (OPTION_RERUN (&A68_JOB) == A68_FALSE) {
68 announce_phase ("plugin compiler");
69 errno = 0;
70 ASSERT (a68_bufprt (options, SNPRINTF_SIZE, "%s %s", optimisation_option (), A68_GCC_OPTIONS) >= 0);
71 #if defined (HAVE_PIC)
72 a68_bufcat (options, " ", BUFFER_SIZE);
73 a68_bufcat (options, HAVE_PIC, BUFFER_SIZE);
74 #endif
75
76 // Before Apple Silicon Mac:
77 //
78 // ASSERT (a68_bufprt (cmd, SNPRINTF_SIZE, "%s -I%s %s -c -o \"%s\" \"%s\"", C_COMPILER, INCLUDE_DIR, options, FILE_BINARY_NAME (&A68_JOB), FILE_OBJECT_NAME (&A68_JOB)) >= 0);
79 // ABEND (system (cmd) != 0, ERROR_ACTION, cmd);
80 // ASSERT (a68_bufprt (cmd, SNPRINTF_SIZE, "ld -export-dynamic -shared -o \"%s\" \"%s\"", FILE_PLUGIN_NAME (&A68_JOB), FILE_BINARY_NAME (&A68_JOB)) >= 0);
81 // ABEND (system (cmd) != 0, ERROR_ACTION, cmd);
82 //
83 // Apple Silicon Mac patches kindly provided by Neil Matthew.
84
85 ASSERT (a68_bufprt (cmd, SNPRINTF_SIZE, "%s %s %s -c -o \"%s\" \"%s\"", C_COMPILER, INCLUDE_DIR, options, FILE_BINARY_NAME (&A68_JOB), FILE_OBJECT_NAME (&A68_JOB)) >= 0);
86 ABEND (system (cmd) != 0, ERROR_ACTION, cmd);
87 ASSERT (a68_bufprt (cmd, SNPRINTF_SIZE, "ld %s -o \"%s\" \"%s\"", EXPORT_DYNAMIC_FLAGS, FILE_PLUGIN_NAME (&A68_JOB), FILE_BINARY_NAME (&A68_JOB)) >= 0);
88 ABEND (system (cmd) != 0, ERROR_ACTION, cmd);
89 a68_rm (FILE_BINARY_NAME (&A68_JOB));
90 }
91 }
92 #endif
93 }
94
95 //! @brief Start interpreter with compiled plugin.
96
97 void plugin_driver_genie (void)
98 {
99 #if defined (BUILD_A68_COMPILER)
100 if (OPTION_RUN_SCRIPT (&A68_JOB)) {
101 rewrite_script_source ();
102 }
103 void *compile_plugin = NULL;
104 if (OPTION_OPT_LEVEL (&A68_JOB) > 0) {
105 char plugin_name[BUFFER_SIZE];
106 void *a68_plugin;
107 struct stat srcstat, objstat;
108 int ret;
109 announce_phase ("plugin dynamic linker");
110 ASSERT (a68_bufprt (plugin_name, SNPRINTF_SIZE, "%s", FILE_PLUGIN_NAME (&A68_JOB)) >= 0);
111 // Correction when pwd is outside LD_PLUGIN_PATH.
112 // The DL cannot be loaded if it is.
113 if (strcmp (plugin_name, a68_basename (plugin_name)) == 0) {
114 ASSERT (a68_bufprt (plugin_name, SNPRINTF_SIZE, "./%s", FILE_PLUGIN_NAME (&A68_JOB)) >= 0);
115 }
116 // Check whether we are doing something rash.
117 ret = stat (FILE_SOURCE_NAME (&A68_JOB), &srcstat);
118 ABEND (ret != 0, ERROR_ACTION, FILE_SOURCE_NAME (&A68_JOB));
119 ret = stat (plugin_name, &objstat);
120 ABEND (ret != 0, ERROR_ACTION, plugin_name);
121 if (OPTION_RERUN (&A68_JOB)) {
122 ABEND (ST_MTIME (&srcstat) > ST_MTIME (&objstat), "plugin outdates source", "cannot RERUN");
123 }
124 // First load a68g itself so compiler code can resolve a68g symbols.
125 a68_plugin = dlopen (NULL, RTLD_NOW | RTLD_GLOBAL);
126 ABEND (a68_plugin == NULL, ERROR_CANNOT_OPEN_PLUGIN, dlerror ());
127 // Then load compiler code.
128 compile_plugin = dlopen (plugin_name, RTLD_NOW | RTLD_GLOBAL);
129 ABEND (compile_plugin == NULL, ERROR_CANNOT_OPEN_PLUGIN, dlerror ());
130 }
131 genie (compile_plugin);
132 // Unload compiler plugin.
133 if (compile_plugin != (void *) NULL) {
134 int ret = dlclose (compile_plugin);
135 ABEND (ret != 0, ERROR_ACTION, dlerror ());
136 }
137 #endif
138 }
139
140 //! @brief Clean files from plugin compiler.
141
142 void plugin_driver_clean (int emitted)
143 {
144 #if defined (BUILD_A68_COMPILER)
145 announce_phase ("clean up intermediate files");
146 if (OPTION_OPT_LEVEL (&A68_JOB) >= OPTIMISE_0 && OPTION_REGRESSION_TEST (&A68_JOB) && !OPTION_KEEP (&A68_JOB)) {
147 if (emitted) {
148 a68_rm (FILE_OBJECT_NAME (&A68_JOB));
149 }
150 a68_rm (FILE_PLUGIN_NAME (&A68_JOB));
151 }
152 if (OPTION_RUN_SCRIPT (&A68_JOB) && !OPTION_KEEP (&A68_JOB)) {
153 if (emitted) {
154 a68_rm (FILE_OBJECT_NAME (&A68_JOB));
155 }
156 a68_rm (FILE_SOURCE_NAME (&A68_JOB));
157 a68_rm (FILE_PLUGIN_NAME (&A68_JOB));
158 } else if (OPTION_COMPILE (&A68_JOB)) {
159 build_script ();
160 if (!OPTION_KEEP (&A68_JOB)) {
161 if (emitted) {
162 a68_rm (FILE_OBJECT_NAME (&A68_JOB));
163 }
164 a68_rm (FILE_PLUGIN_NAME (&A68_JOB));
165 }
166 } else if (OPTION_OPT_LEVEL (&A68_JOB) == OPTIMISE_0 && !OPTION_KEEP (&A68_JOB)) {
167 if (emitted) {
168 a68_rm (FILE_OBJECT_NAME (&A68_JOB));
169 }
170 a68_rm (FILE_PLUGIN_NAME (&A68_JOB));
171 } else if (OPTION_OPT_LEVEL (&A68_JOB) > OPTIMISE_0 && !OPTION_KEEP (&A68_JOB)) {
172 if (emitted) {
173 a68_rm (FILE_OBJECT_NAME (&A68_JOB));
174 }
175 } else if (OPTION_RERUN (&A68_JOB) && !OPTION_KEEP (&A68_JOB)) {
176 if (emitted) {
177 a68_rm (FILE_OBJECT_NAME (&A68_JOB));
178 }
179 }
180 #else
181 (void) emitted;
182 #endif
183 }
© 2002-2024 J.M. van der Veer (jmvdveer@xs4all.nl)
|