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)