LCOV - code coverage report
Current view: top level - vala - valacodecontext.vala (source / functions) Coverage Total Hit
Test: vala 0.57.0.298-a8cae1 Lines: 74.0 % 400 296
Test Date: 2024-04-25 11:34:36 Functions: - 0 0

            Line data    Source code
       1              : /* valacodecontext.vala
       2              :  *
       3              :  * Copyright (C) 2006-2012  Jürg Billeter
       4              :  *
       5              :  * This library is free software; you can redistribute it and/or
       6              :  * modify it under the terms of the GNU Lesser General Public
       7              :  * License as published by the Free Software Foundation; either
       8              :  * version 2.1 of the License, or (at your option) any later version.
       9              : 
      10              :  * This library is distributed in the hope that it will be useful,
      11              :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      12              :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      13              :  * Lesser General Public License for more details.
      14              : 
      15              :  * You should have received a copy of the GNU Lesser General Public
      16              :  * License along with this library; if not, write to the Free Software
      17              :  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
      18              :  *
      19              :  * Author:
      20              :  *      Jürg Billeter <j@bitron.ch>
      21              :  */
      22              : 
      23              : using GLib;
      24              : 
      25              : /**
      26              :  * The root of the code tree.
      27              :  */
      28     10873260 : public class Vala.CodeContext {
      29              :         /**
      30              :          * Enable run-time checks for programming errors.
      31              :          */
      32         7843 :         public bool assert { get; set; }
      33              : 
      34              :         /**
      35              :          * Enable additional run-time checks such as type checks.
      36              :          */
      37        35323 :         public bool checking { get; set; }
      38              : 
      39              :         /**
      40              :          * Do not warn when using deprecated features.
      41              :          */
      42      7384255 :         public bool deprecated { get; set; }
      43              : 
      44              :         /**
      45              :          * Hide the symbols marked as internal
      46              :          */
      47        27012 :         public bool hide_internal { get; set; }
      48              : 
      49              :         /**
      50              :          * Do not check whether used symbols exist in local packages.
      51              :          */
      52        14952 :         public bool since_check { get; set; }
      53              : 
      54              :         /**
      55              :          * Do not warn when using experimental features.
      56              :          */
      57         1600 :         public bool experimental { get; set; }
      58              : 
      59              :         /**
      60              :          * Enable experimental enhancements for non-null types.
      61              :          */
      62      3725613 :         public bool experimental_non_null { get; set; }
      63              : 
      64              :         /**
      65              :          * Enable GObject creation tracing.
      66              :          */
      67         8377 :         public bool gobject_tracing { get; set; }
      68              : 
      69              :         /**
      70              :          * Output C code, don't compile to object code.
      71              :          */
      72         2544 :         public bool ccode_only { get; set; }
      73              : 
      74              :         /**
      75              :          * Command to run pkg-config.
      76              :          */
      77         6010 :         public string pkg_config_command { get; set; default = "pkg-config"; }
      78              : 
      79              :         /**
      80              :          * Enable support for ABI stability.
      81              :          */
      82      1012807 :         public bool abi_stability { get; set; }
      83              : 
      84              :         /**
      85              :          * Output C header file.
      86              :          */
      87       304837 :         public string? header_filename { get; set; }
      88              : 
      89              :         /**
      90              :          * Output internal C header file.
      91              :          */
      92         5554 :         public string? internal_header_filename { get; set; }
      93              : 
      94              :         /**
      95              :          * Base directory used for header_filename in the VAPIs.
      96              :          */
      97         4683 :         public string? includedir { get; set; }
      98              : 
      99              :         /**
     100              :          * Output symbols file.
     101              :          */
     102         5359 :         public string? symbols_filename { get; set; }
     103              : 
     104              :         /**
     105              :          * Compile but do not link.
     106              :          */
     107         2299 :         public bool compile_only { get; set; }
     108              : 
     109              :         /**
     110              :          * Output filename.
     111              :          */
     112         7800 :         public string output { get; set; }
     113              : 
     114              :         /**
     115              :          * Base source directory.
     116              :          */
     117        10303 :         public string basedir { get; set; }
     118              : 
     119              :         /**
     120              :          * Code output directory.
     121              :          */
     122         9123 :         public string directory { get; set; }
     123              : 
     124              :         /**
     125              :          * List of directories where to find .vapi files.
     126              :          */
     127        14367 :         public string[] vapi_directories { get; set; default = {}; }
     128              : 
     129              :         /**
     130              :          * List of directories where to find .gir files.
     131              :          */
     132         6326 :         public string[] gir_directories { get; set; default = {}; }
     133              : 
     134              :         /**
     135              :          * List of directories where to find .metadata files for .gir files.
     136              :          */
     137         6246 :         public string[] metadata_directories { get; set; default = {}; }
     138              : 
     139              :         /**
     140              :          * Produce debug information.
     141              :          */
     142         3376 :         public bool debug { get; set; }
     143              : 
     144              :         /**
     145              :          * Optimization level.
     146              :          */
     147            0 :         public int optlevel { get; set; }
     148              : 
     149              :         /**
     150              :          * Enable memory profiler.
     151              :          */
     152         2336 :         public bool mem_profiler { get; set; }
     153              : 
     154              :         /**
     155              :          * Specifies the optional module initialization method.
     156              :          */
     157         9722 :         public Method module_init_method { get; set; }
     158              : 
     159              :         /**
     160              :          * Keep temporary files produced by the compiler.
     161              :          */
     162         1467 :         public bool save_temps { get; set; }
     163              : 
     164      6115006 :         public Profile profile { get; private set; }
     165              : 
     166         2299 :         public bool verbose_mode { get; set; }
     167              : 
     168         2631 :         public bool version_header { get; set; }
     169              : 
     170          196 :         public bool use_fast_vapi { get; set; }
     171              : 
     172              :         /**
     173              :          * Continue as much as possible after an error.
     174              :          */
     175         1480 :         public bool keep_going { get; set; }
     176              : 
     177              :         /**
     178              :          * Include comments in generated vapi.
     179              :          */
     180        22787 :         public bool vapi_comments { get; set; }
     181              : 
     182              :         /**
     183              :          * Returns true if the target version of glib is greater than or
     184              :          * equal to the specified version.
     185              :          */
     186        11756 :         public bool require_glib_version (int major, int minor) {
     187        11756 :                 return (target_glib_major > major) || (target_glib_major == major && target_glib_minor >= minor);
     188              :         }
     189              : 
     190              :         public bool save_csources {
     191         1664 :                 get { return save_temps; }
     192              :         }
     193              : 
     194        25001 :         public Report report { get; set; default = new Report ();}
     195              : 
     196         6395 :         public Method? entry_point { get; set; }
     197              : 
     198        10261 :         public string entry_point_name { get; set; }
     199              : 
     200         9305 :         public bool run_output { get; set; }
     201              : 
     202         6046 :         public string[] gresources { get; set; default = {}; }
     203              : 
     204         6010 :         public string[] gresources_directories { get; set; default = {}; }
     205              : 
     206         3076 :         private List<SourceFile> source_files = new ArrayList<SourceFile> ();
     207         3076 :         private Map<string,unowned SourceFile> source_files_map = new HashMap<string,unowned SourceFile> (str_hash, str_equal);
     208         3076 :         private List<string> c_source_files = new ArrayList<string> (str_equal);
     209         3076 :         private Namespace _root = new Namespace (null);
     210              : 
     211         3076 :         private List<string> packages = new ArrayList<string> (str_equal);
     212              : 
     213         3076 :         private Set<string> defines = new HashSet<string> (str_hash, str_equal);
     214              : 
     215         1538 :         static StaticPrivate context_stack_key = StaticPrivate ();
     216              : 
     217              :         int target_glib_major;
     218              :         int target_glib_minor;
     219              : 
     220              :         /**
     221              :          * The root namespace of the symbol tree.
     222              :          */
     223              :         public Namespace root {
     224     10254245 :                 get { return _root; }
     225              :         }
     226              : 
     227         9157 :         public SymbolResolver resolver { get; private set; }
     228              : 
     229    160673952 :         public SemanticAnalyzer analyzer { get; private set; }
     230              : 
     231         4614 :         public FlowAnalyzer flow_analyzer { get; private set; }
     232              : 
     233              :         /**
     234              :          * The selected code generator.
     235              :          */
     236         6301 :         public CodeGenerator codegen { get; set; }
     237              : 
     238              :         /**
     239              :          * Mark attributes used by the compiler and report unused at the end.
     240              :          */
     241         4614 :         public UsedAttr used_attr { get; set; }
     242              : 
     243         3076 :         public CodeContext () {
     244         1538 :                 add_default_defines ();
     245              : 
     246         1538 :                 resolver = new SymbolResolver ();
     247         1538 :                 analyzer = new SemanticAnalyzer ();
     248         1538 :                 flow_analyzer = new FlowAnalyzer ();
     249         1538 :                 used_attr = new UsedAttr ();
     250              :         }
     251              : 
     252              :         /**
     253              :          * Return the topmost context from the context stack.
     254              :          */
     255              :         public static CodeContext get () {
     256     10856056 :                 List<CodeContext>* context_stack = context_stack_key.get ();
     257              : 
     258     10856056 :                 if (context_stack == null || context_stack->size == 0) {
     259            0 :                         error ("internal: No context available to get");
     260              :                 }
     261              : 
     262     10856056 :                 return context_stack->get (context_stack->size - 1);
     263              :         }
     264              : 
     265              :         /**
     266              :          * Push the specified context to the context stack.
     267              :          */
     268         1538 :         public static void push (CodeContext context) {
     269         1538 :                 ArrayList<CodeContext>* context_stack = context_stack_key.get ();
     270         1538 :                 if (context_stack == null) {
     271         1538 :                         context_stack = new ArrayList<CodeContext> ();
     272         1538 :                         context_stack_key.set (context_stack, null);
     273              :                 }
     274              : 
     275         1538 :                 context_stack->add (context);
     276              :         }
     277              : 
     278              :         /**
     279              :          * Remove the topmost context from the context stack.
     280              :          */
     281              :         public static void pop () {
     282         1538 :                 List<CodeContext>* context_stack = context_stack_key.get ();
     283              : 
     284         1538 :                 if (context_stack == null || context_stack->size == 0) {
     285            0 :                         error ("internal: No context available to pop");
     286              :                 }
     287              : 
     288         1538 :                 context_stack->remove_at (context_stack->size - 1);
     289              : 
     290         1538 :                 if (context_stack->size == 0) {
     291         1538 :                         delete context_stack;
     292         1538 :                         context_stack_key.set (null, null);
     293              :                 }
     294              :         }
     295              : 
     296              :         /**
     297              :          * Returns the list of source files.
     298              :          *
     299              :          * @return list of source files
     300              :          */
     301         4302 :         public unowned List<SourceFile> get_source_files () {
     302         4302 :                 return source_files;
     303              :         }
     304              : 
     305              :         /**
     306              :          * Returns the list of C source files.
     307              :          *
     308              :          * @return list of C source files
     309              :          */
     310          832 :         public unowned List<string> get_c_source_files () {
     311          832 :                 return c_source_files;
     312              :         }
     313              : 
     314              :         /**
     315              :          * Adds the specified file to the list of source files.
     316              :          *
     317              :          * @param file a source file
     318              :          */
     319         6886 :         public void add_source_file (SourceFile file) {
     320         6886 :                 if (source_files_map.contains (file.filename)) {
     321            0 :                         Report.warning (null, "Ignoring source file `%s', which was already added to this context", file.filename);
     322            0 :                         return;
     323              :                 }
     324              : 
     325         6886 :                 source_files.add (file);
     326         6886 :                 source_files_map.set (file.filename, file);
     327              :         }
     328              : 
     329              :         /**
     330              :          * Returns the source file for a given path.
     331              :          *
     332              :          * @param filename a path to a source file
     333              :          * @return the source file if found
     334              :          */
     335            1 :         public unowned Vala.SourceFile? get_source_file (string filename) {
     336            1 :                 return source_files_map.get (filename);
     337              :         }
     338              : 
     339              :         /**
     340              :          * Adds the specified file to the list of C source files.
     341              :          *
     342              :          * @param file a C source file
     343              :          */
     344            0 :         public void add_c_source_file (string file) {
     345            0 :                 c_source_files.add (file);
     346              :         }
     347              : 
     348              :         /**
     349              :          * Returns the list of used packages.
     350              :          *
     351              :          * @return list of used packages
     352              :          */
     353          832 :         public unowned List<string> get_packages () {
     354          832 :                 return packages;
     355              :         }
     356              : 
     357              :         /**
     358              :          * Returns whether the specified package is being used.
     359              :          *
     360              :          * @param pkg a package name
     361              :          * @return    true if the specified package is being used
     362              :          */
     363        10723 :         public bool has_package (string pkg) {
     364        10723 :                 return packages.contains (pkg);
     365              :         }
     366              : 
     367              :         /**
     368              :          * Adds the specified package to the list of used packages.
     369              :          *
     370              :          * @param pkg a package name
     371              :          */
     372         5149 :         public void add_package (string pkg) {
     373         5149 :                 packages.add (pkg);
     374              :         }
     375              : 
     376              :         /**
     377              :          * Pull the specified package into the context.
     378              :          * The method is tolerant if the package has been already loaded.
     379              :          *
     380              :          * @param pkg a package name
     381              :          * @return false if the package could not be loaded
     382              :          *
     383              :          */
     384        10332 :         public bool add_external_package (string pkg) {
     385        10332 :                 if (has_package (pkg)) {
     386              :                         // ignore multiple occurrences of the same package
     387        10332 :                         return true;
     388              :                 }
     389              : 
     390              :                 // first try .vapi
     391         5103 :                 var path = get_vapi_path (pkg);
     392         5103 :                 if (path == null) {
     393              :                         // try with .gir
     394          124 :                         path = get_gir_path (pkg);
     395              :                 }
     396          124 :                 if (path == null) {
     397            0 :                         Report.error (null, "Package `%s' not found in specified Vala API directories or GObject-Introspection GIR directories", pkg);
     398            0 :                         return false;
     399              :                 }
     400              : 
     401         5103 :                 add_package (pkg);
     402              : 
     403         5103 :                 var rpath = realpath (path);
     404         5103 :                 var source_file = new SourceFile (this, SourceFileType.PACKAGE, path);
     405              : 
     406         5103 :                 add_source_file (source_file);
     407         5103 :                 if (rpath != path) {
     408          325 :                         source_files_map.set (rpath, source_file);
     409              :                 }
     410              : 
     411         5103 :                 if (verbose_mode) {
     412            0 :                         print ("Loaded package `%s'\n", path);
     413              :                 }
     414              : 
     415         5103 :                 var deps_filename = Path.build_path ("/", Path.get_dirname (path), pkg + ".deps");
     416         5103 :                 if (!add_packages_from_file (deps_filename)) {
     417            0 :                         return false;
     418              :                 }
     419              : 
     420         5103 :                 return true;
     421              :         }
     422              : 
     423              :         /**
     424              :          * Read the given filename and pull in packages.
     425              :          * The method is tolerant if the file does not exist.
     426              :          *
     427              :          * @param filename a filename
     428              :          * @return false if an error occurs while reading the file or if a package could not be added
     429              :          */
     430         5199 :         public bool add_packages_from_file (string filename) {
     431         5199 :                 if (!FileUtils.test (filename, FileTest.EXISTS)) {
     432         5199 :                         return true;
     433              :                 }
     434              : 
     435         3343 :                 try {
     436              :                         string contents;
     437         3343 :                         FileUtils.get_contents (filename, out contents);
     438        27605 :                         foreach (string package in contents.split ("\n")) {
     439         8788 :                                 package = package.strip ();
     440         8788 :                                 if (package != "") {
     441         5441 :                                         add_external_package (package);
     442              :                                 }
     443              :                         }
     444              :                 } catch (FileError e) {
     445            0 :                         Report.error (null, "Unable to read dependency file: %s", e.message);
     446            0 :                         return false;
     447              :                 }
     448              : 
     449         5199 :                 return true;
     450              :         }
     451              : 
     452              :         /**
     453              :          * Add the specified source file to the context. Only .vala, .vapi, .gs,
     454              :          * and .c extensions are supported.
     455              :          *
     456              :          * @param filename a filename
     457              :          * @param is_source true to force adding the file as .vala or .gs
     458              :          * @param cmdline true if the file came from the command line.
     459              :          * @return false if the file is not recognized or the file does not exist
     460              :          */
     461         1696 :         public bool add_source_filename (string filename, bool is_source = false, bool cmdline = false) {
     462         1696 :                 if (!FileUtils.test (filename, FileTest.EXISTS)) {
     463            0 :                         Report.error (null, "%s not found", filename);
     464            0 :                         return false;
     465              :                 }
     466              : 
     467         1696 :                 var rpath = realpath (filename);
     468         3392 :                 if (is_source || filename.has_suffix (".vala") || filename.has_suffix (".gs")) {
     469         1696 :                         var source_file = new SourceFile (this, SourceFileType.SOURCE, rpath, null, cmdline);
     470         1696 :                         source_file.relative_filename = filename;
     471              : 
     472         1704 :                         if (profile == Profile.POSIX) {
     473              :                                 // import the Posix namespace by default (namespace of backend-specific standard library)
     474            8 :                                 var ns_ref = new UsingDirective (new UnresolvedSymbol (null, "Posix", null));
     475            8 :                                 source_file.add_using_directive (ns_ref);
     476            8 :                                 root.add_using_directive (ns_ref);
     477         3376 :                         } else if (profile == Profile.GOBJECT) {
     478              :                                 // import the GLib namespace by default (namespace of backend-specific standard library)
     479         1688 :                                 var ns_ref = new UsingDirective (new UnresolvedSymbol (null, "GLib", null));
     480         1688 :                                 source_file.add_using_directive (ns_ref);
     481         1688 :                                 root.add_using_directive (ns_ref);
     482              :                         }
     483              : 
     484         1696 :                         add_source_file (source_file);
     485         1696 :                         if (rpath != filename) {
     486         1696 :                                 source_files_map.set (filename, source_file);
     487              :                         }
     488            0 :                 } else if (filename.has_suffix (".vapi") || filename.has_suffix (".gir")) {
     489            0 :                         var source_file = new SourceFile (this, SourceFileType.PACKAGE, rpath, null, cmdline);
     490            0 :                         source_file.relative_filename = filename;
     491              : 
     492            0 :                         add_source_file (source_file);
     493            0 :                         if (rpath != filename) {
     494            0 :                                 source_files_map.set (filename, source_file);
     495              :                         }
     496            0 :                 } else if (filename.has_suffix (".c")) {
     497            0 :                         add_c_source_file (rpath);
     498            0 :                 } else if (filename.has_suffix (".h")) {
     499              :                         /* Ignore */
     500              :                 } else {
     501            0 :                         Report.error (null, "%s is not a supported source file type. Only .vala, .vapi, .gs, and .c files are supported.", filename);
     502            0 :                         return false;
     503              :                 }
     504              : 
     505         1696 :                 return true;
     506              :         }
     507              : 
     508              :         /**
     509              :          * Visits the complete code tree file by file.
     510              :          * It is possible to add new source files while visiting the tree.
     511              :          *
     512              :          * @param visitor the visitor to be called when traversing
     513              :          */
     514         6118 :         public void accept (CodeVisitor visitor) {
     515         6118 :                 root.accept (visitor);
     516              : 
     517              :                 // support queueing new source files
     518         6118 :                 int index = 0;
     519        61722 :                 while (index < source_files.size) {
     520        27802 :                         var source_file = source_files[index];
     521        27802 :                         source_file.accept (visitor);
     522        27802 :                         index++;
     523              :                 }
     524              :         }
     525              : 
     526              :         /**
     527              :          * Resolve and analyze.
     528              :          */
     529         1429 :         public void check () {
     530         1429 :                 resolver.resolve (this);
     531              : 
     532         1429 :                 if (!keep_going && report.get_errors () > 0) {
     533              :                         return;
     534              :                 }
     535              : 
     536         1423 :                 analyzer.analyze (this);
     537              : 
     538              :                 // Don't run the FlowAnalyzer if we have semantic errors, since
     539              :                 // the messages from FlowAnalyzer will usually be nonsensical.
     540         1423 :                 if (report.get_errors () > 0) {
     541              :                         return;
     542              :                 }
     543              : 
     544          971 :                 flow_analyzer.analyze (this);
     545              : 
     546          971 :                 if (report.get_errors () > 0) {
     547              :                         return;
     548              :                 }
     549              : 
     550          958 :                 used_attr.check_unused (this);
     551              :         }
     552              : 
     553         1557 :         public void add_define (string define) {
     554         1557 :                 if (is_defined (define)) {
     555            0 :                         Report.warning (null, "`%s' is already defined", define);
     556            0 :                         if (/VALA_0_\d+/.match_all (define)) {
     557            0 :                                 Report.warning (null, "`VALA_0_XX' defines are automatically added up to current compiler version in use");
     558            0 :                         } else if (/GLIB_2_\d+/.match_all (define)) {
     559            0 :                                 Report.warning (null, "`GLIB_2_XX' defines are automatically added up to targeted glib version");
     560              :                         }
     561              :                 }
     562         1557 :                 defines.add (define);
     563              :         }
     564              : 
     565        33707 :         public bool is_defined (string define) {
     566        33707 :                 return (define in defines);
     567              :         }
     568              : 
     569         1538 :         void add_default_defines () {
     570         1538 :                 int api_major = 0;
     571         1538 :                 int api_minor = 0;
     572              : 
     573         1538 :                 if (API_VERSION.scanf ("%d.%d", out api_major, out api_minor) != 2
     574         1538 :                     || api_major > 0
     575         1538 :                     || api_minor % 2 != 0) {
     576            0 :                         Report.error (null, "Invalid format for Vala.API_VERSION");
     577            0 :                         return;
     578              :                 }
     579              : 
     580        46140 :                 for (int i = 2; i <= api_minor; i += 2) {
     581        44602 :                         defines.add ("VALA_0_%d".printf (i));
     582              :                 }
     583              : 
     584         1538 :                 target_glib_major = 2;
     585         1538 :                 target_glib_minor = 56;
     586              : 
     587        33836 :                 for (int i = 16; i <= target_glib_minor; i += 2) {
     588        32298 :                         defines.add ("GLIB_2_%d".printf (i));
     589              :                 }
     590              :         }
     591              : 
     592              :         /**
     593              :          * Set the target profile for code generation.
     594              :          *
     595              :          * This must be called once.
     596              :          *
     597              :          * @param profile the profile to use
     598              :          * @param include_stdpkg whether to include profile-specific default packages
     599              :          */
     600         1538 :         public void set_target_profile (Profile profile, bool include_stdpkg = true) {
     601         1538 :                 switch (profile) {
     602              :                 default:
     603              :                 case Profile.GOBJECT:
     604              :                         // default profile
     605         1530 :                         this.profile = profile;
     606         1530 :                         add_define ("GOBJECT");
     607              : 
     608         1530 :                         if (include_stdpkg) {
     609              :                                 /* default packages */
     610         1529 :                                 add_external_package ("glib-2.0");
     611         1529 :                                 add_external_package ("gobject-2.0");
     612              :                         }
     613              :                         break;
     614              :                 case Profile.POSIX:
     615              :                 // case Profile.LIBC:
     616            8 :                         this.profile = profile;
     617            8 :                         add_define ("LIBC");
     618            8 :                         add_define ("POSIX");
     619              : 
     620            8 :                         if (include_stdpkg) {
     621              :                                 /* default package */
     622            8 :                                 add_external_package ("posix");
     623              :                         }
     624              :                         break;
     625              :                 }
     626              :         }
     627              : 
     628              :         /**
     629              :          * Set the target version of glib for code generation.
     630              :          *
     631              :          * This may be called once or not at all.
     632              :          *
     633              :          * @param target_glib a string of the format "%d.%d"
     634              :          */
     635            2 :         public void set_target_glib_version (string target_glib) {
     636            2 :                 int glib_major = 0;
     637            2 :                 int glib_minor = 0;
     638              : 
     639            2 :                 if (target_glib == "auto") {
     640            1 :                         var available_glib = pkg_config_modversion ("glib-2.0");
     641            1 :                         if (available_glib != null && available_glib.scanf ("%d.%d", out glib_major, out glib_minor) >= 2) {
     642            1 :                                 glib_minor++;
     643            1 :                                 glib_minor -= glib_minor % 2;
     644            1 :                                 set_target_glib_version ("%d.%d".printf (glib_major, glib_minor));
     645              :                         } else {
     646            0 :                                 Report.warning (null, "Could not determine the version of `glib-2.0', target version of glib was not set");
     647              :                         }
     648            1 :                         return;
     649              :                 }
     650              : 
     651            1 :                 glib_major = target_glib_major;
     652            1 :                 glib_minor = target_glib_minor;
     653              : 
     654            1 :                 if (target_glib != null && target_glib.scanf ("%d.%d", out glib_major, out glib_minor) != 2
     655            1 :                     || glib_minor % 2 != 0) {
     656            0 :                         Report.error (null, "Only a stable version of GLib can be targeted, use MAJOR.MINOR format with MINOR as an even number");
     657              :                 }
     658              : 
     659            1 :                 if (glib_major != 2) {
     660            0 :                         Report.error (null, "This version of valac only supports GLib 2");
     661              :                 }
     662              : 
     663            1 :                 if (glib_minor <= target_glib_minor) {
     664              :                         // no additional defines needed
     665              :                         return;
     666              :                 }
     667              : 
     668           39 :                 for (int i = target_glib_major + 2; i <= glib_minor; i += 2) {
     669           38 :                         defines.add ("GLIB_2_%d".printf (i));
     670              :                 }
     671              : 
     672            1 :                 target_glib_major = glib_major;
     673            1 :                 target_glib_minor = glib_minor;
     674              :         }
     675              : 
     676         5103 :         public string? get_vapi_path (string pkg) {
     677         5103 :                 var path = get_file_path (pkg + ".vapi", "vala" + Config.PACKAGE_SUFFIX + "/vapi", "vala/vapi", vapi_directories);
     678              : 
     679         5227 :                 if (path == null) {
     680              :                         /* last chance: try the package compiled-in vapi dir */
     681          124 :                         var filename = Path.build_path ("/", Config.PACKAGE_DATADIR, "vapi", pkg + ".vapi");
     682          124 :                         if (FileUtils.test (filename, FileTest.EXISTS)) {
     683            0 :                                 path = filename;
     684              :                         }
     685              :                 }
     686              : 
     687              :                 return path;
     688              :         }
     689              : 
     690          124 :         public string? get_gir_path (string gir) {
     691          124 :                 const string GIR_SUFFIX = "gir-1.0";
     692          124 :                 string girname = gir + ".gir";
     693          124 :                 string path = null;
     694              : 
     695          124 :                 foreach (unowned string dir in gir_directories) {
     696            0 :                         path = Path.build_path ("/", dir, girname);
     697            0 :                         if (FileUtils.test (path, FileTest.EXISTS | FileTest.IS_REGULAR)) {
     698            0 :                                 return path;
     699              :                         }
     700              :                 }
     701              : 
     702              :                 // Search $GI_GIR_PATH
     703          124 :                 unowned string? gi_gir_path = Environment.get_variable ("GI_GIR_PATH");
     704          124 :                 if (gi_gir_path != null) {
     705            0 :                         var gir_dirs = gi_gir_path.split (Path.SEARCHPATH_SEPARATOR_S);
     706            0 :                         foreach (unowned string dir in gir_dirs) {
     707            0 :                                 path = Path.build_path ("/", dir, girname);
     708            0 :                                 if (FileUtils.test (path, FileTest.EXISTS | FileTest.IS_REGULAR)) {
     709            0 :                                         return path;
     710              :                                 }
     711              :                         }
     712              :                 }
     713              : 
     714              :                 // Search $XDG_DATA_HOME
     715          124 :                 path = Path.build_path ("/", Environment.get_user_data_dir (), GIR_SUFFIX, girname);
     716          124 :                 if (FileUtils.test (path, FileTest.EXISTS | FileTest.IS_REGULAR)) {
     717            0 :                         return path;
     718              :                 }
     719              : 
     720              :                 // Search $XDG_DATA_DIRS
     721          372 :                 foreach (unowned string dir in Environment.get_system_data_dirs ()) {
     722          248 :                         path = Path.build_path ("/", dir, GIR_SUFFIX, girname);
     723          248 :                         if (FileUtils.test (path, FileTest.EXISTS | FileTest.IS_REGULAR)) {
     724          124 :                                 return path;
     725              :                         }
     726              :                 }
     727              : 
     728              :                 // Search $GI_GIRDIR set by user or retrieved from gobject-introspection-1.0.pc
     729            0 :                 path = Path.build_path ("/", Config.GI_GIRDIR, girname);
     730            0 :                 if (FileUtils.test (path, FileTest.EXISTS | FileTest.IS_REGULAR)) {
     731            0 :                         return path;
     732              :                 }
     733              : 
     734              :                 // Search /usr/share
     735            0 :                 path = Path.build_path ("/", "/usr", "share", GIR_SUFFIX, girname);
     736            0 :                 if (FileUtils.test (path, FileTest.EXISTS | FileTest.IS_REGULAR)) {
     737            0 :                         return path;
     738              :                 }
     739              : 
     740            0 :                 return null;
     741              :         }
     742              : 
     743            8 :         public string? get_gresource_path (string gresource, string resource) {
     744            8 :                 var filename = get_file_path (resource, null, null, { Path.get_dirname (gresource) });
     745            8 :                 if (filename == null) {
     746            0 :                         filename = get_file_path (resource, null, null, gresources_directories);
     747              :                 }
     748              :                 return filename;
     749              :         }
     750              : 
     751              :         /*
     752              :          * Returns the .metadata file associated with the given .gir file.
     753              :          */
     754           92 :         public string? get_metadata_path (string gir_filename) {
     755           92 :                 var basename = Path.get_basename (gir_filename);
     756           92 :                 var metadata_basename = "%s.metadata".printf (basename.substring (0, basename.length - ".gir".length));
     757              : 
     758              :                 // look into metadata directories
     759           92 :                 var metadata_filename = get_file_path (metadata_basename, null, null, metadata_directories);
     760           92 :                 if (metadata_filename != null) {
     761            2 :                         return metadata_filename;
     762              :                 }
     763              : 
     764              :                 // look into the same directory of .gir
     765           90 :                 metadata_filename = Path.build_path ("/", Path.get_dirname (gir_filename), metadata_basename);
     766           90 :                 if (FileUtils.test (metadata_filename, FileTest.EXISTS)) {
     767            0 :                         return metadata_filename;
     768              :                 }
     769              : 
     770           90 :                 return null;
     771              :         }
     772              : 
     773         5203 :         string? get_file_path (string basename, string? versioned_data_dir, string? data_dir, string[] directories) {
     774         5203 :                 string filename = null;
     775              : 
     776         5203 :                 if (directories != null) {
     777         5325 :                         foreach (unowned string dir in directories) {
     778         5201 :                                 filename = Path.build_path ("/", dir, basename);
     779         5201 :                                 if (FileUtils.test (filename, FileTest.EXISTS)) {
     780         4989 :                                         return filename;
     781              :                                 }
     782              :                         }
     783              :                 }
     784              : 
     785          214 :                 if (data_dir != null) {
     786          496 :                         foreach (unowned string dir in Environment.get_system_data_dirs ()) {
     787          248 :                                 filename = Path.build_path ("/", dir, data_dir, basename);
     788          248 :                                 if (FileUtils.test (filename, FileTest.EXISTS)) {
     789            0 :                                         return filename;
     790              :                                 }
     791              :                         }
     792              :                 }
     793              : 
     794          214 :                 if (versioned_data_dir != null) {
     795          496 :                         foreach (unowned string dir in Environment.get_system_data_dirs ()) {
     796          248 :                                 filename = Path.build_path ("/", dir, versioned_data_dir, basename);
     797          248 :                                 if (FileUtils.test (filename, FileTest.EXISTS)) {
     798            0 :                                         return filename;
     799              :                                 }
     800              :                         }
     801              :                 }
     802              : 
     803          214 :                 return null;
     804              :         }
     805              : 
     806              :         /*
     807              :          * Create make-style depfile for use by build systems.
     808              :          */
     809            0 :         void write_depfile (string filename, List<string> deps) {
     810            0 :                 var stream = FileStream.open (filename, "w");
     811              : 
     812            0 :                 if (stream == null) {
     813            0 :                         Report.error (null, "unable to open `%s' for writing", filename);
     814            0 :                         return;
     815              :                 }
     816              : 
     817            0 :                 bool first = true;
     818            0 :                 foreach (var dep in deps) {
     819            0 :                         if (first) {
     820            0 :                                 first = false;
     821            0 :                                 stream.printf ("%s: ", filename);
     822              :                         } else {
     823            0 :                                 stream.puts (" \\\n\t");
     824              :                         }
     825            0 :                         stream.printf ("%s", dep);
     826              :                 }
     827              :                 // Don't write newlines to otherwise empty files to work around
     828              :                 // https://github.com/ninja-build/ninja/issues/2357
     829            0 :                 if (!first) {
     830            0 :                         stream.puts ("\n\n");
     831              :                 }
     832              :         }
     833              : 
     834            0 :         public void write_dependencies (string filename) {
     835            0 :                 List<string> fastvapi_files = new ArrayList<string> (str_equal);
     836            0 :                 foreach (var src in source_files) {
     837            0 :                         if (src.file_type == SourceFileType.FAST && src.used) {
     838            0 :                                 fastvapi_files.add (src.filename);
     839              :                         }
     840              :                 }
     841            0 :                 write_depfile (filename, fastvapi_files);
     842              :         }
     843              : 
     844            0 :         public void write_external_dependencies (string filename) {
     845            0 :                 List<string> external_files = new ArrayList<string> (str_equal);
     846            0 :                 foreach (var src in source_files) {
     847            0 :                         if (src.file_type != SourceFileType.SOURCE && src.used) {
     848            0 :                                 external_files.add (src.filename);
     849              :                         }
     850              :                 }
     851            0 :                 write_depfile (filename, external_files);
     852              :         }
     853              : 
     854        35539 :         private static bool ends_with_dir_separator (string s) {
     855        35539 :                 return Path.is_dir_separator (s.get_char (s.length - 1));
     856              :         }
     857              : 
     858              :         /**
     859              :          * Returns canonicalized absolute pathname
     860              :          * ported from glibc
     861              :          *
     862              :          * @param name the path being checked
     863              :          * @return a canonicalized absolute pathname
     864              :          */
     865         8268 :         public static string realpath (string name) {
     866              :                 string rpath;
     867              : 
     868              :                 // start of path component
     869              :                 weak string start;
     870              :                 // end of path component
     871              :                 weak string end;
     872              : 
     873         8268 :                 if (!Path.is_absolute (name)) {
     874              :                         // relative path
     875         3490 :                         rpath = Environment.get_current_dir ();
     876              : 
     877         3490 :                         start = end = name;
     878              :                 } else {
     879              :                         // set start after root
     880         4778 :                         start = end = Path.skip_root (name);
     881              : 
     882              :                         // extract root
     883         4778 :                         rpath = name.substring (0, (int) ((char*) start - (char*) name));
     884              :                 }
     885              : 
     886         8268 :                 long root_len = (long) ((char*) Path.skip_root (rpath) - (char*) rpath);
     887              : 
     888        36147 :                 for (; start.get_char () != 0; start = end) {
     889              :                         // skip sequence of multiple path-separators
     890        47490 :                         while (Path.is_dir_separator (start.get_char ())) {
     891        19611 :                                 start = start.next_char ();
     892              :                         }
     893              : 
     894              :                         // find end of path component
     895              :                         long len = 0;
     896       247933 :                         for (end = start; end.get_char () != 0 && !Path.is_dir_separator (end.get_char ()); end = end.next_char ()) {
     897       220054 :                                 len++;
     898              :                         }
     899              : 
     900        27879 :                         if (len == 0) {
     901              :                                 break;
     902        27879 :                         } else if (len == 1 && start.get_char () == '.') {
     903              :                                 // do nothing
     904        26178 :                         } else if (len == 2 && start.has_prefix ("..")) {
     905              :                                 // back up to previous component, ignore if at root already
     906          170 :                                 if (rpath.length > root_len) {
     907         1433 :                                         do {
     908         1263 :                                                 rpath = rpath.substring (0, rpath.length - 1);
     909         1263 :                                         } while (!ends_with_dir_separator (rpath));
     910              :                                 }
     911              :                         } else {
     912        26008 :                                 if (!ends_with_dir_separator (rpath)) {
     913        21130 :                                         rpath += Path.DIR_SEPARATOR_S;
     914              :                                 }
     915              : 
     916              :                                 // don't use len, substring works on bytes
     917        26008 :                                 rpath += start.substring (0, (long)((char*)end - (char*)start));
     918              :                         }
     919              :                 }
     920              : 
     921         8268 :                 if (rpath.length > root_len && ends_with_dir_separator (rpath)) {
     922            0 :                         rpath = rpath.substring (0, rpath.length - 1);
     923              :                 }
     924              : 
     925              :                 if (Path.DIR_SEPARATOR != '/') {
     926              :                         // don't use backslashes internally,
     927              :                         // to avoid problems in #include directives
     928              :                         string[] components = rpath.split ("\\");
     929              :                         rpath = string.joinv ("/", components);
     930              :                 }
     931              : 
     932              :                 return rpath;
     933              :         }
     934              : 
     935         2502 :         public bool pkg_config_exists (string package_name) {
     936         2502 :                 string pc = pkg_config_command + " --exists " + package_name;
     937              :                 int exit_status;
     938              : 
     939            0 :                 try {
     940         5004 :                         Process.spawn_command_line_sync (pc, null, null, out exit_status);
     941         2502 :                         return (0 == exit_status);
     942              :                 } catch (SpawnError e) {
     943            0 :                         Report.error (null, e.message);
     944            0 :                         return false;
     945              :                 }
     946              :         }
     947              : 
     948         2895 :         public string? pkg_config_modversion (string package_name) {
     949         2895 :                 string pc = pkg_config_command + " --silence-errors --modversion " + package_name;
     950         2895 :                 string? output = null;
     951              :                 int exit_status;
     952              : 
     953         2895 :                 try {
     954         2895 :                         Process.spawn_command_line_sync (pc, out output, null, out exit_status);
     955         2895 :                         if (exit_status == 0) {
     956         2882 :                                 output = output[0:-1];
     957         2882 :                                 if (output == "") {
     958            0 :                                         output = null;
     959              :                                 }
     960              :                         } else {
     961           13 :                                 output = null;
     962              :                         }
     963              :                 } catch (SpawnError e) {
     964            0 :                         output = null;
     965              :                 }
     966              : 
     967         2895 :                 return output;
     968              :         }
     969              : 
     970          824 :         public string? pkg_config_compile_flags (string package_name) {
     971          824 :                 string pc = pkg_config_command + " --cflags";
     972          824 :                 if (!compile_only) {
     973          824 :                         pc += " --libs";
     974              :                 }
     975          824 :                 pc += package_name;
     976              : 
     977          824 :                 string? output = null;
     978              :                 int exit_status;
     979              : 
     980          824 :                 try {
     981          824 :                         Process.spawn_command_line_sync (pc, out output, null, out exit_status);
     982          824 :                         if (exit_status != 0) {
     983            0 :                                 Report.error (null, "%s exited with status %d", pkg_config_command, exit_status);
     984            0 :                                 return null;
     985              :                         }
     986              :                 } catch (SpawnError e) {
     987            0 :                         Report.error (null, e.message);
     988            0 :                         output = null;
     989              :                 }
     990              : 
     991          824 :                 return output;
     992              :         }
     993              : 
     994            0 :         public string? pkg_config_variable (string package_name, string variable_name) {
     995            0 :                 string pc = pkg_config_command + " --variable="+ variable_name + " " + package_name;
     996            0 :                 string? output = null;
     997              :                 int exit_status;
     998              : 
     999            0 :                 try {
    1000            0 :                         Process.spawn_command_line_sync (pc, out output, null, out exit_status);
    1001            0 :                         if (exit_status != 0) {
    1002            0 :                                 Report.error (null, "%s exited with status %d", pkg_config_command, exit_status);
    1003            0 :                                 return null;
    1004              :                         }
    1005              :                 } catch (SpawnError e) {
    1006            0 :                         Report.error (null, e.message);
    1007            0 :                         output = null;
    1008              :                 }
    1009              : 
    1010            0 :                 return output;
    1011              :         }
    1012              : }
        

Generated by: LCOV version 2.0-1