• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /netgear-WNDR4500v2-V1.0.0.60_1.0.38/ap/gpl/timemachine/gettext-0.17/gettext-tools/gnulib-lib/
1/* Compile a C# program.
2   Copyright (C) 2003-2007 Free Software Foundation, Inc.
3   Written by Bruno Haible <bruno@clisp.org>, 2003.
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
16   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
17
18#include <config.h>
19#include <alloca.h>
20
21/* Specification.  */
22#include "csharpcomp.h"
23
24#include <errno.h>
25#include <stdio.h>
26#include <stdlib.h>
27#include <string.h>
28
29#include "execute.h"
30#include "pipe.h"
31#include "wait-process.h"
32#include "sh-quote.h"
33#include "safe-read.h"
34#include "xmalloca.h"
35#include "error.h"
36#include "gettext.h"
37
38#define _(str) gettext (str)
39
40
41/* Survey of C# compilers.
42
43   Program    from
44
45   cscc       pnet
46   mcs        mono
47   csc        sscli
48
49   We try the CIL interpreters in the following order:
50     1. "cscc", because it is a completely free system.
51     2. "mcs", because it is a free system but doesn't integrate so well
52        with Unix. (Command line options start with / instead of -. Errors go
53        to stdout instead of stderr. Source references are printed as
54        "file(lineno)" instead of "file:lineno:".)
55     3. "csc", although it is not free, because it is a kind of "reference
56        implementation" of C#.
57   But the order can be changed through the --enable-csharp configuration
58   option.
59 */
60
61static int
62compile_csharp_using_pnet (const char * const *sources,
63			   unsigned int sources_count,
64			   const char * const *libdirs,
65			   unsigned int libdirs_count,
66			   const char * const *libraries,
67			   unsigned int libraries_count,
68			   const char *output_file, bool output_is_library,
69			   bool optimize, bool debug,
70			   bool verbose)
71{
72  static bool cscc_tested;
73  static bool cscc_present;
74
75  if (!cscc_tested)
76    {
77      /* Test for presence of cscc:
78	 "cscc --version >/dev/null 2>/dev/null"  */
79      char *argv[3];
80      int exitstatus;
81
82      argv[0] = "cscc";
83      argv[1] = "--version";
84      argv[2] = NULL;
85      exitstatus = execute ("cscc", "cscc", argv, false, false, true, true,
86			    true, false);
87      cscc_present = (exitstatus == 0);
88      cscc_tested = true;
89    }
90
91  if (cscc_present)
92    {
93      unsigned int argc;
94      char **argv;
95      char **argp;
96      int exitstatus;
97      unsigned int i;
98
99      argc =
100	1 + (output_is_library ? 1 : 0) + 2 + 2 * libdirs_count
101	+ 2 * libraries_count + (optimize ? 1 : 0) + (debug ? 1 : 0)
102	+ sources_count;
103      argv = (char **) xmalloca ((argc + 1) * sizeof (char *));
104
105      argp = argv;
106      *argp++ = "cscc";
107      if (output_is_library)
108	*argp++ = "-shared";
109      *argp++ = "-o";
110      *argp++ = (char *) output_file;
111      for (i = 0; i < libdirs_count; i++)
112	{
113	  *argp++ = "-L";
114	  *argp++ = (char *) libdirs[i];
115	}
116      for (i = 0; i < libraries_count; i++)
117	{
118	  *argp++ = "-l";
119	  *argp++ = (char *) libraries[i];
120	}
121      if (optimize)
122	*argp++ = "-O";
123      if (debug)
124	*argp++ = "-g";
125      for (i = 0; i < sources_count; i++)
126	{
127	  const char *source_file = sources[i];
128	  if (strlen (source_file) >= 10
129	      && memcmp (source_file + strlen (source_file) - 10, ".resources",
130			 10) == 0)
131	    {
132	      char *option = (char *) xmalloca (12 + strlen (source_file) + 1);
133
134	      memcpy (option, "-fresources=", 12);
135	      strcpy (option + 12, source_file);
136	      *argp++ = option;
137	    }
138	  else
139	    *argp++ = (char *) source_file;
140	}
141      *argp = NULL;
142      /* Ensure argv length was correctly calculated.  */
143      if (argp - argv != argc)
144	abort ();
145
146      if (verbose)
147	{
148	  char *command = shell_quote_argv (argv);
149	  printf ("%s\n", command);
150	  free (command);
151	}
152
153      exitstatus = execute ("cscc", "cscc", argv, false, false, false, false,
154			    true, true);
155
156      for (i = 0; i < sources_count; i++)
157	if (argv[argc - sources_count + i] != sources[i])
158	  freea (argv[argc - sources_count + i]);
159      freea (argv);
160
161      return (exitstatus != 0);
162    }
163  else
164    return -1;
165}
166
167static int
168compile_csharp_using_mono (const char * const *sources,
169			   unsigned int sources_count,
170			   const char * const *libdirs,
171			   unsigned int libdirs_count,
172			   const char * const *libraries,
173			   unsigned int libraries_count,
174			   const char *output_file, bool output_is_library,
175			   bool optimize, bool debug,
176			   bool verbose)
177{
178  static bool mcs_tested;
179  static bool mcs_present;
180
181  if (!mcs_tested)
182    {
183      /* Test for presence of mcs:
184	 "mcs --version >/dev/null 2>/dev/null"
185	 and (to exclude an unrelated 'mcs' program on QNX 6)
186	 "mcs --version 2>/dev/null | grep Mono >/dev/null"  */
187      char *argv[3];
188      pid_t child;
189      int fd[1];
190      int exitstatus;
191
192      argv[0] = "mcs";
193      argv[1] = "--version";
194      argv[2] = NULL;
195      child = create_pipe_in ("mcs", "mcs", argv, DEV_NULL, true, true, false,
196			      fd);
197      mcs_present = false;
198      if (child != -1)
199	{
200	  /* Read the subprocess output, and test whether it contains the
201	     string "Mono".  */
202	  char c[4];
203	  size_t count = 0;
204
205	  while (safe_read (fd[0], &c[count], 1) > 0)
206	    {
207	      count++;
208	      if (count == 4)
209		{
210		  if (memcmp (c, "Mono", 4) == 0)
211		    mcs_present = true;
212		  c[0] = c[1]; c[1] = c[2]; c[2] = c[3];
213		  count--;
214		}
215	    }
216
217	  close (fd[0]);
218
219	  /* Remove zombie process from process list, and retrieve exit
220	     status.  */
221	  exitstatus =
222	    wait_subprocess (child, "mcs", false, true, true, false);
223	  if (exitstatus != 0)
224	    mcs_present = false;
225	}
226      mcs_tested = true;
227    }
228
229  if (mcs_present)
230    {
231      unsigned int argc;
232      char **argv;
233      char **argp;
234      pid_t child;
235      int fd[1];
236      FILE *fp;
237      char *line[2];
238      size_t linesize[2];
239      size_t linelen[2];
240      unsigned int l;
241      int exitstatus;
242      unsigned int i;
243
244      argc =
245	1 + (output_is_library ? 1 : 0) + 1 + libdirs_count + libraries_count
246	+ (debug ? 1 : 0) + sources_count;
247      argv = (char **) xmalloca ((argc + 1) * sizeof (char *));
248
249      argp = argv;
250      *argp++ = "mcs";
251      if (output_is_library)
252	*argp++ = "-target:library";
253      {
254	char *option = (char *) xmalloca (5 + strlen (output_file) + 1);
255	memcpy (option, "-out:", 5);
256	strcpy (option + 5, output_file);
257	*argp++ = option;
258      }
259      for (i = 0; i < libdirs_count; i++)
260	{
261	  char *option = (char *) xmalloca (5 + strlen (libdirs[i]) + 1);
262	  memcpy (option, "-lib:", 5);
263	  strcpy (option + 5, libdirs[i]);
264	  *argp++ = option;
265	}
266      for (i = 0; i < libraries_count; i++)
267	{
268	  char *option = (char *) xmalloca (11 + strlen (libraries[i]) + 4 + 1);
269	  memcpy (option, "-reference:", 11);
270	  memcpy (option + 11, libraries[i], strlen (libraries[i]));
271	  strcpy (option + 11 + strlen (libraries[i]), ".dll");
272	  *argp++ = option;
273	}
274      if (debug)
275	*argp++ = "-debug";
276      for (i = 0; i < sources_count; i++)
277	{
278	  const char *source_file = sources[i];
279	  if (strlen (source_file) >= 10
280	      && memcmp (source_file + strlen (source_file) - 10, ".resources",
281			 10) == 0)
282	    {
283	      char *option = (char *) xmalloca (10 + strlen (source_file) + 1);
284
285	      memcpy (option, "-resource:", 10);
286	      strcpy (option + 10, source_file);
287	      *argp++ = option;
288	    }
289	  else
290	    *argp++ = (char *) source_file;
291	}
292      *argp = NULL;
293      /* Ensure argv length was correctly calculated.  */
294      if (argp - argv != argc)
295	abort ();
296
297      if (verbose)
298	{
299	  char *command = shell_quote_argv (argv);
300	  printf ("%s\n", command);
301	  free (command);
302	}
303
304      child = create_pipe_in ("mcs", "mcs", argv, NULL, false, true, true, fd);
305
306      /* Read the subprocess output, copying it to stderr.  Drop the last
307	 line if it starts with "Compilation succeeded".  */
308      fp = fdopen (fd[0], "r");
309      if (fp == NULL)
310	error (EXIT_FAILURE, errno, _("fdopen() failed"));
311      line[0] = NULL; linesize[0] = 0;
312      line[1] = NULL; linesize[1] = 0;
313      l = 0;
314      for (;;)
315	{
316	  linelen[l] = getline (&line[l], &linesize[l], fp);
317	  if (linelen[l] == (size_t)(-1))
318	    break;
319	  l = (l + 1) % 2;
320	  if (line[l] != NULL)
321	    fwrite (line[l], 1, linelen[l], stderr);
322	}
323      l = (l + 1) % 2;
324      if (line[l] != NULL
325	  && !(linelen[l] >= 21
326	       && memcmp (line[l], "Compilation succeeded", 21) == 0))
327	fwrite (line[l], 1, linelen[l], stderr);
328      if (line[0] != NULL)
329	free (line[0]);
330      if (line[1] != NULL)
331	free (line[1]);
332      fclose (fp);
333
334      /* Remove zombie process from process list, and retrieve exit status.  */
335      exitstatus = wait_subprocess (child, "mcs", false, false, true, true);
336
337      for (i = 1 + (output_is_library ? 1 : 0);
338	   i < 1 + (output_is_library ? 1 : 0)
339	       + 1 + libdirs_count + libraries_count;
340	   i++)
341	freea (argv[i]);
342      for (i = 0; i < sources_count; i++)
343	if (argv[argc - sources_count + i] != sources[i])
344	  freea (argv[argc - sources_count + i]);
345      freea (argv);
346
347      return (exitstatus != 0);
348    }
349  else
350    return -1;
351}
352
353static int
354compile_csharp_using_sscli (const char * const *sources,
355			    unsigned int sources_count,
356			    const char * const *libdirs,
357			    unsigned int libdirs_count,
358			    const char * const *libraries,
359			    unsigned int libraries_count,
360			    const char *output_file, bool output_is_library,
361			    bool optimize, bool debug,
362			    bool verbose)
363{
364  static bool csc_tested;
365  static bool csc_present;
366
367  if (!csc_tested)
368    {
369      /* Test for presence of csc:
370	 "csc -help >/dev/null 2>/dev/null \
371	  && ! { csc -help 2>/dev/null | grep -i chicken > /dev/null; }"  */
372      char *argv[3];
373      pid_t child;
374      int fd[1];
375      int exitstatus;
376
377      argv[0] = "csc";
378      argv[1] = "-help";
379      argv[2] = NULL;
380      child = create_pipe_in ("csc", "csc", argv, DEV_NULL, true, true, false,
381			      fd);
382      csc_present = false;
383      if (child != -1)
384	{
385	  /* Read the subprocess output, and test whether it contains the
386	     string "chicken".  */
387	  char c[7];
388	  size_t count = 0;
389
390	  csc_present = true;
391	  while (safe_read (fd[0], &c[count], 1) > 0)
392	    {
393	      if (c[count] >= 'A' && c[count] <= 'Z')
394		c[count] += 'a' - 'A';
395	      count++;
396	      if (count == 7)
397		{
398		  if (memcmp (c, "chicken", 7) == 0)
399		    csc_present = false;
400		  c[0] = c[1]; c[1] = c[2]; c[2] = c[3];
401		  c[3] = c[4]; c[4] = c[5]; c[5] = c[6];
402		  count--;
403		}
404	    }
405
406	  close (fd[0]);
407
408	  /* Remove zombie process from process list, and retrieve exit
409	     status.  */
410	  exitstatus =
411	    wait_subprocess (child, "csc", false, true, true, false);
412	  if (exitstatus != 0)
413	    csc_present = false;
414	}
415      csc_tested = true;
416    }
417
418  if (csc_present)
419    {
420      unsigned int argc;
421      char **argv;
422      char **argp;
423      int exitstatus;
424      unsigned int i;
425
426      argc =
427	1 + 1 + 1 + libdirs_count + libraries_count
428	+ (optimize ? 1 : 0) + (debug ? 1 : 0) + sources_count;
429      argv = (char **) xmalloca ((argc + 1) * sizeof (char *));
430
431      argp = argv;
432      *argp++ = "csc";
433      *argp++ =
434	(char *) (output_is_library ? "-target:library" : "-target:exe");
435      {
436	char *option = (char *) xmalloca (5 + strlen (output_file) + 1);
437	memcpy (option, "-out:", 5);
438	strcpy (option + 5, output_file);
439	*argp++ = option;
440      }
441      for (i = 0; i < libdirs_count; i++)
442	{
443	  char *option = (char *) xmalloca (5 + strlen (libdirs[i]) + 1);
444	  memcpy (option, "-lib:", 5);
445	  strcpy (option + 5, libdirs[i]);
446	  *argp++ = option;
447	}
448      for (i = 0; i < libraries_count; i++)
449	{
450	  char *option = (char *) xmalloca (11 + strlen (libraries[i]) + 4 + 1);
451	  memcpy (option, "-reference:", 11);
452	  memcpy (option + 11, libraries[i], strlen (libraries[i]));
453	  strcpy (option + 11 + strlen (libraries[i]), ".dll");
454	  *argp++ = option;
455	}
456      if (optimize)
457	*argp++ = "-optimize+";
458      if (debug)
459	*argp++ = "-debug+";
460      for (i = 0; i < sources_count; i++)
461	{
462	  const char *source_file = sources[i];
463	  if (strlen (source_file) >= 10
464	      && memcmp (source_file + strlen (source_file) - 10, ".resources",
465			 10) == 0)
466	    {
467	      char *option = (char *) xmalloca (10 + strlen (source_file) + 1);
468
469	      memcpy (option, "-resource:", 10);
470	      strcpy (option + 10, source_file);
471	      *argp++ = option;
472	    }
473	  else
474	    *argp++ = (char *) source_file;
475	}
476      *argp = NULL;
477      /* Ensure argv length was correctly calculated.  */
478      if (argp - argv != argc)
479	abort ();
480
481      if (verbose)
482	{
483	  char *command = shell_quote_argv (argv);
484	  printf ("%s\n", command);
485	  free (command);
486	}
487
488      exitstatus = execute ("csc", "csc", argv, false, false, false, false,
489			    true, true);
490
491      for (i = 2; i < 3 + libdirs_count + libraries_count; i++)
492	freea (argv[i]);
493      for (i = 0; i < sources_count; i++)
494	if (argv[argc - sources_count + i] != sources[i])
495	  freea (argv[argc - sources_count + i]);
496      freea (argv);
497
498      return (exitstatus != 0);
499    }
500  else
501    return -1;
502}
503
504bool
505compile_csharp_class (const char * const *sources,
506		      unsigned int sources_count,
507		      const char * const *libdirs,
508		      unsigned int libdirs_count,
509		      const char * const *libraries,
510		      unsigned int libraries_count,
511		      const char *output_file,
512		      bool optimize, bool debug,
513		      bool verbose)
514{
515  bool output_is_library =
516    (strlen (output_file) >= 4
517     && memcmp (output_file + strlen (output_file) - 4, ".dll", 4) == 0);
518  int result;
519
520  /* First try the C# implementation specified through --enable-csharp.  */
521#if CSHARP_CHOICE_PNET
522  result = compile_csharp_using_pnet (sources, sources_count,
523				      libdirs, libdirs_count,
524				      libraries, libraries_count,
525				      output_file, output_is_library,
526				      optimize, debug, verbose);
527  if (result >= 0)
528    return (bool) result;
529#endif
530
531#if CSHARP_CHOICE_MONO
532  result = compile_csharp_using_mono (sources, sources_count,
533				      libdirs, libdirs_count,
534				      libraries, libraries_count,
535				      output_file, output_is_library,
536				      optimize, debug, verbose);
537  if (result >= 0)
538    return (bool) result;
539#endif
540
541  /* Then try the remaining C# implementations in our standard order.  */
542#if !CSHARP_CHOICE_PNET
543  result = compile_csharp_using_pnet (sources, sources_count,
544				      libdirs, libdirs_count,
545				      libraries, libraries_count,
546				      output_file, output_is_library,
547				      optimize, debug, verbose);
548  if (result >= 0)
549    return (bool) result;
550#endif
551
552#if !CSHARP_CHOICE_MONO
553  result = compile_csharp_using_mono (sources, sources_count,
554				      libdirs, libdirs_count,
555				      libraries, libraries_count,
556				      output_file, output_is_library,
557				      optimize, debug, verbose);
558  if (result >= 0)
559    return (bool) result;
560#endif
561
562  result = compile_csharp_using_sscli (sources, sources_count,
563				       libdirs, libdirs_count,
564				       libraries, libraries_count,
565				       output_file, output_is_library,
566				       optimize, debug, verbose);
567  if (result >= 0)
568    return (bool) result;
569
570  error (0, 0, _("C# compiler not found, try installing pnet"));
571  return true;
572}
573