1 /* Compile a C# program.
2 Copyright (C) 2003-2005 Free Software Foundation, Inc.
3 Written by Bruno Haible <bruno@clisp.org>, 2003.
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 2, or (at your option)
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.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software Foundation,
17 Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
25 #include "csharpcomp.h"
34 #include "wait-process.h"
37 #include "safe-read.h"
42 #define _(str) gettext (str)
45 /* Survey of C# compilers.
53 We try the CIL interpreters in the following order:
54 1. "cscc", because it is a completely free system.
55 2. "mcs", because it is a free system but doesn't integrate so well
56 with Unix. (Command line options start with / instead of -. Errors go
57 to stdout instead of stderr. Source references are printed as
58 "file(lineno)" instead of "file:lineno:".)
59 3. "csc", although it is not free, because it is a kind of "reference
60 implementation" of C#.
61 But the order can be changed through the --enable-csharp configuration
66 compile_csharp_using_pnet (const char * const *sources
,
67 unsigned int sources_count
,
68 const char * const *libdirs
,
69 unsigned int libdirs_count
,
70 const char * const *libraries
,
71 unsigned int libraries_count
,
72 const char *output_file
, bool output_is_library
,
73 bool optimize
, bool debug
,
76 static bool cscc_tested
;
77 static bool cscc_present
;
81 /* Test for presence of cscc:
82 "cscc --version >/dev/null 2>/dev/null" */
87 argv
[1] = "--version";
89 exitstatus
= execute ("cscc", "cscc", argv
, false, false, true, true,
91 cscc_present
= (exitstatus
== 0);
104 1 + (output_is_library
? 1 : 0) + 2 + 2 * libdirs_count
105 + 2 * libraries_count
+ (optimize
? 1 : 0) + (debug
? 1 : 0)
107 argv
= (char **) xallocsa ((argc
+ 1) * sizeof (char *));
111 if (output_is_library
)
114 *argp
++ = (char *) output_file
;
115 for (i
= 0; i
< libdirs_count
; i
++)
118 *argp
++ = (char *) libdirs
[i
];
120 for (i
= 0; i
< libraries_count
; i
++)
123 *argp
++ = (char *) libraries
[i
];
129 for (i
= 0; i
< sources_count
; i
++)
131 const char *source_file
= sources
[i
];
132 if (strlen (source_file
) >= 9
133 && memcmp (source_file
+ strlen (source_file
) - 9, ".resource",
136 char *option
= (char *) xallocsa (12 + strlen (source_file
) + 1);
138 memcpy (option
, "-fresources=", 12);
139 strcpy (option
+ 12, source_file
);
143 *argp
++ = (char *) source_file
;
146 /* Ensure argv length was correctly calculated. */
147 if (argp
- argv
!= argc
)
152 char *command
= shell_quote_argv (argv
);
153 printf ("%s\n", command
);
157 exitstatus
= execute ("cscc", "cscc", argv
, false, false, false, false,
160 for (i
= 0; i
< sources_count
; i
++)
161 if (argv
[argc
- sources_count
+ i
] != sources
[i
])
162 freesa (argv
[argc
- sources_count
+ i
]);
165 return (exitstatus
!= 0);
172 compile_csharp_using_mono (const char * const *sources
,
173 unsigned int sources_count
,
174 const char * const *libdirs
,
175 unsigned int libdirs_count
,
176 const char * const *libraries
,
177 unsigned int libraries_count
,
178 const char *output_file
, bool output_is_library
,
179 bool optimize
, bool debug
,
182 static bool mcs_tested
;
183 static bool mcs_present
;
187 /* Test for presence of mcs:
188 "mcs --version >/dev/null 2>/dev/null" */
193 argv
[1] = "--version";
195 exitstatus
= execute ("mcs", "mcs", argv
, false, false, true, true, true,
197 mcs_present
= (exitstatus
== 0);
217 1 + (output_is_library
? 1 : 0) + 2 + 2 * libdirs_count
218 + 2 * libraries_count
+ (debug
? 1 : 0) + sources_count
;
219 argv
= (char **) xallocsa ((argc
+ 1) * sizeof (char *));
223 if (output_is_library
)
224 *argp
++ = "-target:library";
226 *argp
++ = (char *) output_file
;
227 for (i
= 0; i
< libdirs_count
; i
++)
230 *argp
++ = (char *) libdirs
[i
];
232 for (i
= 0; i
< libraries_count
; i
++)
235 *argp
++ = (char *) libraries
[i
];
239 for (i
= 0; i
< sources_count
; i
++)
241 const char *source_file
= sources
[i
];
242 if (strlen (source_file
) >= 9
243 && memcmp (source_file
+ strlen (source_file
) - 9, ".resource",
246 char *option
= (char *) xallocsa (10 + strlen (source_file
) + 1);
248 memcpy (option
, "-resource:", 10);
249 strcpy (option
+ 10, source_file
);
253 *argp
++ = (char *) source_file
;
256 /* Ensure argv length was correctly calculated. */
257 if (argp
- argv
!= argc
)
262 char *command
= shell_quote_argv (argv
);
263 printf ("%s\n", command
);
267 child
= create_pipe_in ("mcs", "mcs", argv
, NULL
, false, true, true, fd
);
269 /* Read the subprocess output, copying it to stderr. Drop the last
270 line if it starts with "Compilation succeeded". */
271 fp
= fdopen (fd
[0], "r");
273 error (EXIT_FAILURE
, errno
, _("fdopen() failed"));
274 line
[0] = NULL
; linesize
[0] = 0;
275 line
[1] = NULL
; linesize
[1] = 0;
279 linelen
[l
] = getline (&line
[l
], &linesize
[l
], fp
);
280 if (linelen
[l
] == (size_t)(-1))
284 fwrite (line
[l
], 1, linelen
[l
], stderr
);
288 && !(linelen
[l
] >= 21
289 && memcmp (line
[l
], "Compilation succeeded", 21) == 0))
290 fwrite (line
[l
], 1, linelen
[l
], stderr
);
297 /* Remove zombie process from process list, and retrieve exit status. */
298 exitstatus
= wait_subprocess (child
, "mcs", false, false, true, true);
300 for (i
= 0; i
< sources_count
; i
++)
301 if (argv
[argc
- sources_count
+ i
] != sources
[i
])
302 freesa (argv
[argc
- sources_count
+ i
]);
305 return (exitstatus
!= 0);
312 compile_csharp_using_sscli (const char * const *sources
,
313 unsigned int sources_count
,
314 const char * const *libdirs
,
315 unsigned int libdirs_count
,
316 const char * const *libraries
,
317 unsigned int libraries_count
,
318 const char *output_file
, bool output_is_library
,
319 bool optimize
, bool debug
,
322 static bool csc_tested
;
323 static bool csc_present
;
327 /* Test for presence of csc:
328 "csc -help >/dev/null 2>/dev/null \
329 && ! { csc -help 2>/dev/null | grep -i chicken > /dev/null; }" */
338 child
= create_pipe_in ("csc", "csc", argv
, DEV_NULL
, true, true, false,
343 /* Read the subprocess output, and test whether it contains the
349 while (safe_read (fd
[0], &c
[count
], 1) > 0)
351 if (c
[count
] >= 'A' && c
[count
] <= 'Z')
352 c
[count
] += 'a' - 'A';
356 if (memcmp (c
, "chicken", 7) == 0)
358 c
[0] = c
[1]; c
[1] = c
[2]; c
[2] = c
[3];
359 c
[3] = c
[4]; c
[4] = c
[5]; c
[5] = c
[6];
366 /* Remove zombie process from process list, and retrieve exit
369 wait_subprocess (child
, "csc", false, true, true, false);
385 1 + 1 + 1 + libdirs_count
+ libraries_count
386 + (optimize
? 1 : 0) + (debug
? 1 : 0) + sources_count
;
387 argv
= (char **) xallocsa ((argc
+ 1) * sizeof (char *));
391 *argp
++ = (output_is_library
? "-target:library" : "-target:exe");
393 char *option
= (char *) xallocsa (5 + strlen (output_file
) + 1);
394 memcpy (option
, "-out:", 5);
395 strcpy (option
+ 5, output_file
);
398 for (i
= 0; i
< libdirs_count
; i
++)
400 char *option
= (char *) xallocsa (5 + strlen (libdirs
[i
]) + 1);
401 memcpy (option
, "-lib:", 5);
402 strcpy (option
+ 5, libdirs
[i
]);
405 for (i
= 0; i
< libraries_count
; i
++)
407 char *option
= (char *) xallocsa (11 + strlen (libraries
[i
]) + 1);
408 memcpy (option
, "-reference:", 11);
409 strcpy (option
+ 11, libraries
[i
]);
413 *argp
++ = "-optimize+";
416 for (i
= 0; i
< sources_count
; i
++)
418 const char *source_file
= sources
[i
];
419 if (strlen (source_file
) >= 9
420 && memcmp (source_file
+ strlen (source_file
) - 9, ".resource",
423 char *option
= (char *) xallocsa (10 + strlen (source_file
) + 1);
425 memcpy (option
, "-resource:", 10);
426 strcpy (option
+ 10, source_file
);
430 *argp
++ = (char *) source_file
;
433 /* Ensure argv length was correctly calculated. */
434 if (argp
- argv
!= argc
)
439 char *command
= shell_quote_argv (argv
);
440 printf ("%s\n", command
);
444 exitstatus
= execute ("csc", "csc", argv
, false, false, false, false,
447 for (i
= 2; i
< 3 + libdirs_count
+ libraries_count
; i
++)
449 for (i
= 0; i
< sources_count
; i
++)
450 if (argv
[argc
- sources_count
+ i
] != sources
[i
])
451 freesa (argv
[argc
- sources_count
+ i
]);
454 return (exitstatus
!= 0);
461 compile_csharp_class (const char * const *sources
,
462 unsigned int sources_count
,
463 const char * const *libdirs
,
464 unsigned int libdirs_count
,
465 const char * const *libraries
,
466 unsigned int libraries_count
,
467 const char *output_file
,
468 bool optimize
, bool debug
,
471 bool output_is_library
=
472 (strlen (output_file
) >= 4
473 && memcmp (output_file
+ strlen (output_file
) - 4, ".dll", 4) == 0);
476 /* First try the C# implementation specified through --enable-csharp. */
477 #if CSHARP_CHOICE_PNET
478 result
= compile_csharp_using_pnet (sources
, sources_count
,
479 libdirs
, libdirs_count
,
480 libraries
, libraries_count
,
481 output_file
, output_is_library
,
482 optimize
, debug
, verbose
);
484 return (bool) result
;
487 #if CSHARP_CHOICE_MONO
488 result
= compile_csharp_using_mono (sources
, sources_count
,
489 libdirs
, libdirs_count
,
490 libraries
, libraries_count
,
491 output_file
, output_is_library
,
492 optimize
, debug
, verbose
);
494 return (bool) result
;
497 /* Then try the remaining C# implementations in our standard order. */
498 #if !CSHARP_CHOICE_PNET
499 result
= compile_csharp_using_pnet (sources
, sources_count
,
500 libdirs
, libdirs_count
,
501 libraries
, libraries_count
,
502 output_file
, output_is_library
,
503 optimize
, debug
, verbose
);
505 return (bool) result
;
508 #if !CSHARP_CHOICE_MONO
509 result
= compile_csharp_using_mono (sources
, sources_count
,
510 libdirs
, libdirs_count
,
511 libraries
, libraries_count
,
512 output_file
, output_is_library
,
513 optimize
, debug
, verbose
);
515 return (bool) result
;
518 result
= compile_csharp_using_sscli (sources
, sources_count
,
519 libdirs
, libdirs_count
,
520 libraries
, libraries_count
,
521 output_file
, output_is_library
,
522 optimize
, debug
, verbose
);
524 return (bool) result
;
526 error (0, 0, _("C# compiler not found, try installing pnet"));