|
|
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-2026 J. Marcel van der Veer [algol68g@algol68genie.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 }
© 2001-2026 J.M. van der Veer
jmvdveer@algol68genie.nl