mail-notification

Fork of Jean-Yves Lefort's mail-notification, a tray icon to notify of new mail
git clone https://code.djc.id.au/git/mail-notification/

jbsrc/lib/src/core/jb-tests.c (14366B) - raw

      1 /*
      2  * JB, the Jean-Yves Lefort's Build System
      3  * Copyright (C) 2008 Jean-Yves Lefort <jylefort@brutele.be>
      4  *
      5  * This program is free software; you can redistribute it and/or modify
      6  * it under the terms of the GNU General Public License as published by
      7  * the Free Software Foundation; either version 3 of the License, or
      8  * (at your option) any later version.
      9  *
     10  * This program 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
     13  * GNU General Public License for more details.
     14  *
     15  * You should have received a copy of the GNU General Public License along
     16  * with this program; if not, write to the Free Software Foundation, Inc.,
     17  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
     18  */
     19 
     20 #include <stdio.h>
     21 #include <string.h>
     22 #include <unistd.h>
     23 #include <glib.h>
     24 #include "jb-util.h"
     25 #include "jb-variable.h"
     26 #include "jb-compile-options.h"
     27 #include "jb-tests.h"
     28 #include "jb-feature.h"
     29 
     30 void
     31 jb_check_host_system (void)
     32 {
     33   char *output;
     34   gboolean status = FALSE;
     35 
     36   if (jb_variable_get_variable("host-cpu") != NULL)
     37     return;			/* already checked */
     38 
     39   jb_message_checking("the host system type");
     40 
     41   if (jb_exec(&output, NULL, "jbsrc/tools/config.sub `jbsrc/tools/config.guess`"))
     42     {
     43       char **fields;
     44       int len;
     45 
     46       fields = g_strsplit(output, "-", 0);
     47       len = g_strv_length(fields);
     48 
     49       if (len == 3)
     50 	{
     51 	  jb_variable_set_string("host-cpu", fields[0]);
     52 	  jb_variable_set_string("host-manufacturer", fields[1]);
     53 	  jb_variable_set_string("host-kernel", NULL);
     54 	  jb_variable_set_string("host-os", fields[2]);
     55 	  status = TRUE;
     56 	}
     57       else if (len == 4)
     58 	{
     59 	  jb_variable_set_string("host-cpu", fields[0]);
     60 	  jb_variable_set_string("host-manufacturer", fields[1]);
     61 	  jb_variable_set_string("host-kernel", fields[2]);
     62 	  jb_variable_set_string("host-os", fields[3]);
     63 	  status = TRUE;
     64 	}
     65 
     66       g_strfreev(fields);
     67     }
     68 
     69   if (status)
     70     jb_message_result_string(output);
     71   else
     72     jb_message_result_string("unknown");
     73 
     74   g_free(output);
     75 
     76   if (! status)
     77     jb_error("unable to determine host system type");
     78 }
     79 
     80 void
     81 jb_register_program (const char *name, JBVariableFlags flags)
     82 {
     83   char *description;
     84   char *program;
     85 
     86   g_return_if_fail(name != NULL);
     87 
     88   description = g_strdup_printf("%s program", name);
     89 
     90   program = g_find_program_in_path(name);
     91 
     92   jb_variable_add_string(name,
     93 			 description,
     94 			 jb_variable_group_external_programs,
     95 			 flags,
     96 			 program);
     97 
     98   g_free(description);
     99   g_free(program);
    100 }
    101 
    102 /* the program must have been registered with jb_register_program() */
    103 gboolean
    104 jb_check_program (const char *name)
    105 {
    106   static GHashTable *checked_programs = NULL;
    107   JBVariable *variable;
    108   const char *program;
    109   gboolean result = FALSE;
    110 
    111   g_return_val_if_fail(name != NULL, FALSE);
    112 
    113   /* do not check for the same program twice */
    114   if (checked_programs != NULL)
    115     {
    116       gpointer checked_result;
    117 
    118       if (g_hash_table_lookup_extended(checked_programs, name, NULL, &checked_result))
    119 	return GPOINTER_TO_INT(checked_result);
    120     }
    121   else
    122     checked_programs = g_hash_table_new(g_str_hash, g_str_equal);
    123 
    124   jb_message_checking("for %s", name);
    125 
    126   variable = jb_variable_get_variable_or_error(name);
    127 
    128   program = g_value_get_string(&variable->value);
    129 
    130   if (variable->user_set)
    131     {
    132       char *absolute_program;
    133 
    134       absolute_program = g_find_program_in_path(program);
    135       if (absolute_program != NULL)
    136 	{
    137 	  jb_message_result_string(absolute_program);
    138 	  g_value_take_string(&variable->value, absolute_program);
    139 	  result = TRUE;
    140 	}
    141       else
    142 	{
    143 	  jb_message_result_string_format("not found (\"%s\" was specified but was not found, is a directory or is not executable)", program);
    144 	  g_value_set_string(&variable->value, NULL);
    145 	}
    146     }
    147   else
    148     {
    149       if (program != NULL)
    150 	{
    151 	  jb_message_result_string(program);
    152 	  result = TRUE;
    153 	}
    154       else
    155 	jb_message_result_string("not found");
    156     }
    157 
    158   g_hash_table_insert(checked_programs, g_strdup(name), GINT_TO_POINTER(result));
    159 
    160   return result;
    161 }
    162 
    163 void
    164 jb_require_program (const char *name)
    165 {
    166   g_return_if_fail(name != NULL);
    167 
    168   if (! jb_check_program(name))
    169     jb_error("required program \"%s\" not found", name);
    170 }
    171 
    172 static void
    173 log_c_test (const char *filename, const char *action)
    174 {
    175   char *source;
    176   char **lines;
    177   int i;
    178 
    179   source = jb_read_file_or_exit(filename);
    180   lines = g_strsplit(source, "\n", 0);
    181   g_free(source);
    182 
    183   jb_log("attempting to %s program %s:", action, filename);
    184 
    185   for (i = 0; lines[i] != NULL; i++)
    186     {
    187       const char *line = lines[i];
    188 
    189       /* do not output a spurious empty last line */
    190       if (*line == '\0' && lines[i + 1] == NULL)
    191 	break;
    192 
    193       jb_log("%4i %s", i + 1, lines[i]);
    194     }
    195 
    196   jb_log(JB_SEPARATOR);
    197 
    198   g_strfreev(lines);
    199 }
    200 
    201 gboolean
    202 jb_test_compile (const char *filename,
    203 		 const char *cflags,
    204 		 const char *cppflags)
    205 {
    206   g_return_val_if_fail(filename != NULL, FALSE);
    207 
    208   log_c_test(filename, "compile");
    209 
    210   return jb_exec_expand(NULL, NULL,
    211 			"$cc -c -o build/test.o"
    212 			" $cflags $extra-cflags"
    213 			" $cppflags $extra-cppflags"
    214 			" $filename",
    215 			"extra-cflags", cflags,
    216 			"extra-cppflags", cppflags,
    217 			"filename", filename,
    218 			NULL);
    219 }
    220 
    221 gboolean
    222 jb_test_compile_string (const char *str,
    223 			const char *cflags,
    224 			const char *cppflags)
    225 {
    226   g_return_val_if_fail(str != NULL, FALSE);
    227 
    228   jb_write_file_or_exit("build/test.c", str);
    229 
    230   return jb_test_compile("build/test.c", cflags, cppflags);
    231 }
    232 
    233 gboolean
    234 jb_test_link (const char *filename,
    235 	      const char *cflags,
    236 	      const char *cppflags,
    237 	      const char *ldflags,
    238 	      const char *libs)
    239 {
    240   g_return_val_if_fail(filename != NULL, FALSE);
    241 
    242   log_c_test(filename, "link");
    243 
    244   return jb_exec_expand(NULL, NULL,
    245 			"$cc -o build/test"
    246 			" $cflags $extra-cflags"
    247 			" $cppflags $extra-cppflags"
    248 			" $ldflags $extra-ldflags"
    249 			" $filename"
    250 			" $libs $extra-libs",
    251 			"filename", filename,
    252 			"extra-cflags", cflags,
    253 			"extra-cppflags", cppflags,
    254 			"extra-ldflags", ldflags,
    255 			"extra-libs", libs,
    256 			NULL);
    257 }
    258 
    259 gboolean
    260 jb_test_link_string (const char *str,
    261 		     const char *cflags,
    262 		     const char *cppflags,
    263 		     const char *ldflags,
    264 		     const char *libs)
    265 {
    266   g_return_val_if_fail(str != NULL, FALSE);
    267 
    268   jb_write_file_or_exit("build/test.c", str);
    269 
    270   return jb_test_link("build/test.c", cflags, cppflags, ldflags, libs);
    271 }
    272 
    273 gboolean
    274 jb_test_run (const char *filename,
    275 	     const char *cflags,
    276 	     const char *cppflags,
    277 	     const char *ldflags,
    278 	     const char *libs)
    279 {
    280   g_return_val_if_fail(filename != NULL, FALSE);
    281 
    282   if (! jb_test_link(filename, cflags, cppflags, ldflags, libs))
    283     return FALSE;
    284 
    285   return jb_exec(NULL, NULL, "build/test");
    286 }
    287 
    288 gboolean
    289 jb_test_run_string (const char *str,
    290 		    const char *cflags,
    291 		    const char *cppflags,
    292 		    const char *ldflags,
    293 		    const char *libs)
    294 {
    295   g_return_val_if_fail(str != NULL, FALSE);
    296 
    297   jb_write_file_or_exit("build/test.c", str);
    298 
    299   return jb_test_run("build/test.c", cflags, cppflags, ldflags, libs);
    300 }
    301 
    302 gboolean
    303 jb_check_functions (const char *functions, const char *libname)
    304 {
    305   char **functions_array;
    306   int i;
    307   GString *checking_message;
    308   GString *program;
    309   char *libs = NULL;
    310   gboolean result;
    311 
    312   g_return_val_if_fail(functions != NULL, FALSE);
    313 
    314   functions_array = g_strsplit(functions, " ", 0);
    315 
    316   checking_message = g_string_new("for ");
    317 
    318   for (i = 0; functions_array[i] != NULL; i++)
    319     {
    320       if (i != 0)
    321 	g_string_append_printf(checking_message, ", ");
    322 
    323       g_string_append_printf(checking_message, "%s()", functions_array[i]);
    324     }
    325 
    326   if (libname)
    327     g_string_append_printf(checking_message, " in -l%s", libname);
    328   else
    329     g_string_append(checking_message, " in libc");
    330 
    331   jb_message_checking("%s", checking_message->str);
    332   g_string_free(checking_message, TRUE);
    333 
    334   program = g_string_new(NULL);
    335 
    336   /*
    337    * Quoting c.m4 in autoconf: "Override any GCC internal prototype to
    338    * avoid an error. Use char because int might match the return type
    339    * of a GCC builtin and then its argument prototype would still
    340    * apply."
    341    */
    342   for (i = 0; functions_array[i] != NULL; i++)
    343     g_string_append_printf(program, "char %s ();\n", functions_array[i]);
    344 
    345   g_string_append(program, "int main () {");
    346 
    347   for (i = 0; functions_array[i] != NULL; i++)
    348     g_string_append_printf(program, " %s();", functions_array[i]);
    349 
    350   g_string_append(program, " }\n");
    351 
    352   if (libname)
    353     libs = g_strdup_printf("-l%s", libname);
    354 
    355   result = jb_test_link_string(program->str, NULL, NULL, NULL, libs);
    356 
    357   g_string_free(program, TRUE);
    358   g_free(libs);
    359 
    360   jb_message_result_bool(result);
    361 
    362   return result;
    363 }
    364 
    365 gboolean
    366 jb_check_packages (const char *group_name,
    367 		   const char *varprefix,
    368 		   const char *packages)
    369 {
    370   char *quoted_packages;
    371   char *cflags = NULL;
    372   char *libs = NULL;
    373   char *error = NULL;
    374   gboolean status;
    375 
    376   g_return_val_if_fail(group_name != NULL, FALSE);
    377   g_return_val_if_fail(varprefix != NULL, FALSE);
    378   g_return_val_if_fail(packages != NULL, FALSE);
    379   g_return_val_if_fail(jb_feature_is_enabled(&jb_pkg_config_feature), FALSE);
    380 
    381   jb_require_program("pkg-config");
    382 
    383   jb_message_checking("for %s", group_name);
    384 
    385   quoted_packages = g_shell_quote(packages);
    386 
    387   status = jb_exec_expand(&cflags, NULL, "$pkg-config --cflags $packages",
    388 			  "packages", quoted_packages,
    389 			  NULL)
    390     && jb_exec_expand(&libs, NULL, "$pkg-config --libs $packages",
    391 		      "packages", quoted_packages,
    392 		      NULL);
    393 
    394   if (status)
    395     jb_variable_set_package_flags(varprefix, cflags, NULL, NULL, libs);
    396   else
    397     jb_exec_expand(NULL, &error, "$pkg-config --print-errors $packages",
    398 		   "packages", quoted_packages,
    399 		   NULL);
    400 
    401   g_free(quoted_packages);
    402   g_free(cflags);
    403   g_free(libs);
    404 
    405   jb_message_result_bool(status);
    406 
    407   if (error != NULL)
    408     {
    409       jb_warning("%s", error);
    410       g_free(error);
    411     }
    412 
    413   return status;
    414 }
    415 
    416 /*
    417  * If one or more options (bool variables) in the provided
    418  * NULL-terminated list are enabled, checks for the specified
    419  * packages. If the packages are not found, disable the provided
    420  * options.
    421  */
    422 void
    423 jb_check_packages_for_options (const char *group_name,
    424 			       const char *varprefix,
    425 			       const char *packages,
    426 			       ...)
    427 {
    428   GSList *options = NULL;
    429   va_list args;
    430   const char *option;
    431   gboolean needs_packages = FALSE;
    432 
    433   g_return_if_fail(group_name != NULL);
    434   g_return_if_fail(varprefix != NULL);
    435   g_return_if_fail(packages != NULL);
    436   g_return_if_fail(jb_feature_is_enabled(&jb_pkg_config_feature));
    437 
    438   va_start(args, packages);
    439   while ((option = va_arg(args, const char *)) != NULL)
    440     {
    441       options = g_slist_append(options, (gpointer) option);
    442 
    443       if (jb_variable_get_bool(option))
    444 	needs_packages = TRUE;
    445     }
    446   va_end(args);
    447 
    448   if (needs_packages && ! jb_check_packages(group_name, varprefix, packages))
    449     {
    450       GSList *l;
    451 
    452       JB_LIST_FOREACH(l, options)
    453 	{
    454 	  option = l->data;
    455 
    456 	  if (jb_variable_get_bool(option))
    457 	    {
    458 	      jb_warning("disabling option \"%s\" since %s was not found", option, group_name);
    459 	      jb_variable_set_bool(option, FALSE);
    460 	    }
    461 	}
    462     }
    463 
    464   g_slist_free(options);
    465 }
    466 
    467 void
    468 jb_require_packages (const char *group_name,
    469 		     const char *varprefix,
    470 		     const char *packages)
    471 {
    472   g_return_if_fail(group_name != NULL);
    473   g_return_if_fail(varprefix != NULL);
    474   g_return_if_fail(packages != NULL);
    475   g_return_if_fail(jb_feature_is_enabled(&jb_pkg_config_feature));
    476 
    477   if (! jb_check_packages(group_name, varprefix, packages))
    478     jb_error("unable to find %s", group_name);
    479 }
    480 
    481 char *
    482 jb_get_package_variable (const char *package, const char *variable)
    483 {
    484   char *value;
    485 
    486   g_return_val_if_fail(package != NULL, NULL);
    487   g_return_val_if_fail(variable != NULL, NULL);
    488   g_return_val_if_fail(jb_feature_is_enabled(&jb_pkg_config_feature), FALSE);
    489 
    490   jb_require_program("pkg-config");
    491 
    492   if (! jb_exec_expand(&value, NULL, "$pkg-config --variable=$variable $package",
    493 		       "variable", variable,
    494 		       "package", package,
    495 		       NULL))
    496     {
    497       g_free(value);
    498       value = NULL;
    499     }
    500 
    501   return value;
    502 }
    503 
    504 void
    505 jb_check_cc_dependency_style (void)
    506 {
    507   if (! jb_variable_get_bool("cc-dependency-tracking"))
    508     return; /* we don't need to know since we will not use it */
    509 
    510   jb_message_checking("the C compiler dependency style");
    511 
    512   /* make sure they do not exist beforehand */
    513   unlink("build/test.o");
    514   unlink("build/test.o.deps");
    515 
    516   if (jb_test_compile_string("#include <stdio.h>\n"
    517 			     "int main () {}\n",
    518 			     "-MT build/test.o -MD -MP -MF build/test.o.deps",
    519 			     NULL)
    520       && g_file_test("build/test.o", G_FILE_TEST_IS_REGULAR)
    521       && g_file_test("build/test.o.deps", G_FILE_TEST_IS_REGULAR))
    522     jb_message_result_string("GCC");
    523   else
    524     {
    525       jb_message_result_string("unknown, disabling dependency tracking");
    526       jb_variable_set_bool("cc-dependency-tracking", FALSE);
    527     }
    528 }
    529 
    530 void
    531 jb_check_glibc (void)
    532 {
    533   gboolean result;
    534 
    535   jb_message_checking("for the GNU C library");
    536   result = jb_test_compile_string("#include <features.h>\n"
    537 				  "int main() {\n"
    538 				  "#ifndef __GLIBC__\n"
    539 				  "#error \"glibc not found\"\n"
    540 				  "#endif\n"
    541 				  "}\n",
    542 				  NULL,
    543 				  NULL);
    544   jb_message_result_bool(result);
    545 
    546   jb_variable_set_bool("glibc", result);
    547 }
    548 
    549 static gboolean
    550 check_reentrant_resolver_real (gboolean *result)
    551 {
    552   const char *os;
    553   int freebsd_major;
    554   int freebsd_minor;
    555 
    556   if (! strcmp(jb_variable_get_string("host-kernel"), "linux"))
    557     {
    558       *result = TRUE;
    559       return TRUE;
    560     }
    561 
    562   os = jb_variable_get_string("host-os");
    563 
    564   if (sscanf(os, "freebsd%d.%d", &freebsd_major, &freebsd_minor) == 2)
    565     {
    566       /* FreeBSD >= 5.3 */
    567       *result = (freebsd_major == 5 && freebsd_minor >= 3) || freebsd_major >= 6;
    568       return TRUE;
    569     }
    570 
    571   if (g_str_has_prefix(os, "netbsd") || g_str_has_prefix(os, "openbsd"))
    572     {
    573       *result = FALSE;
    574       return TRUE;
    575     }
    576 
    577   return FALSE;			/* unknown */
    578 }
    579 
    580 void
    581 jb_check_reentrant_dns_resolver (void)
    582 {
    583   gboolean result;
    584 
    585   jb_check_host_system();
    586 
    587   jb_message_checking("if the DNS resolver is reentrant");
    588 
    589   if (check_reentrant_resolver_real(&result))
    590     {
    591       jb_message_result_bool(result);
    592       if (result)
    593 	jb_compile_options_add_cppflags(jb_compile_options, "-DHAVE_REENTRANT_RESOLVER");
    594     }
    595   else
    596     jb_message_result_string("unknown, assuming it is not");
    597 }