Titan Core Initial Contribution
[deliverable/titan.core.git] / compiler2 / makefile.c
1 ///////////////////////////////////////////////////////////////////////////////
2 // Copyright (c) 2000-2014 Ericsson Telecom AB
3 // All rights reserved. This program and the accompanying materials
4 // are made available under the terms of the Eclipse Public License v1.0
5 // which accompanies this distribution, and is available at
6 // http://www.eclipse.org/legal/epl-v10.html
7 ///////////////////////////////////////////////////////////////////////////////
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <string.h>
11 #include <stdarg.h>
12 #include <unistd.h>
13 #include <errno.h>
14 #include <ctype.h>
15 #if defined SOLARIS || defined SOLARIS8
16 # include <sys/utsname.h>
17 #endif
18
19 #include "../common/memory.h"
20 #include "../common/path.h"
21 #include "../common/version_internal.h"
22 #include "../common/userinfo.h"
23 #include "ttcn3/ttcn3_preparser.h"
24 #include "asn1/asn1_preparser.h"
25
26 #ifdef LICENSE
27 #include "../common/license.h"
28 #endif
29
30 #include "xpather.h"
31
32 static const char *program_name = NULL;
33 static unsigned int error_count = 0;
34 static boolean suppress_warnings = FALSE;
35
36 void ERROR(const char *fmt, ...)
37 {
38 va_list parameters;
39 fprintf(stderr, "%s: error: ", program_name);
40 va_start(parameters, fmt);
41 vfprintf(stderr, fmt, parameters);
42 va_end(parameters);
43 fprintf(stderr, "\n");
44 fflush(stderr);
45 error_count++;
46 }
47
48 void WARNING(const char *fmt, ...)
49 {
50 va_list parameters;
51 if (suppress_warnings) return;
52 fprintf(stderr, "%s: warning: ", program_name);
53 va_start(parameters, fmt);
54 vfprintf(stderr, fmt, parameters);
55 va_end(parameters);
56 putc('\n', stderr);
57 fflush(stderr);
58 }
59
60 void NOTIFY(const char *fmt, ...)
61 {
62 va_list parameters;
63 va_start(parameters, fmt);
64 vfprintf(stderr, fmt, parameters);
65 va_end(parameters);
66 putc('\n', stderr);
67 fflush(stderr);
68 }
69
70 void DEBUG(unsigned level, const char *fmt, ...)
71 {
72 va_list parameters;
73 fprintf(stderr, "%*s", 2 * level, "");
74 va_start(parameters, fmt);
75 vfprintf(stderr, fmt, parameters);
76 va_end(parameters);
77 putc('\n', stderr);
78 fflush(stderr);
79 }
80
81 void path_error(const char *fmt, ...)
82 {
83 va_list ap;
84 char *err_msg;
85 va_start(ap, fmt);
86 err_msg = mprintf_va_list(fmt, ap);
87 va_end(ap);
88 ERROR("%s", err_msg);
89 Free(err_msg);
90 }
91
92
93 #if defined SOLARIS || defined SOLARIS8
94 /** Automatic detection of Solaris version based on uname() system call.
95 * Distinguishing is needed because some socket functions use socklen_t
96 * (which is an alias for unsigned int) as length arguments on Solaris 8.
97 * On Solaris 2.6 the argument type is simply int and no socklen_t or other
98 * alias exists.
99 * Note: It was discovered later that Solaris 7 (which is used rarely within
100 * Ericsson) already uses socklen_t thus the SOLARIS8 platform identifier is a
101 * bit misleading. */
102 static const char *get_platform_string(void)
103 {
104 struct utsname name;
105 int major, minor;
106 if (uname(&name) < 0) {
107 WARNING("System call uname() failed: %s", strerror(errno));
108 errno = 0;
109 return "SOLARIS";
110 }
111 if (sscanf(name.release, "%d.%d", &major, &minor) == 2 && major == 5) {
112 if (minor <= 6) return "SOLARIS";
113 else return "SOLARIS8";
114 } else {
115 ERROR("Invalid OS release: %s", name.release);
116 return "SOLARIS";
117 }
118 }
119 #elif defined LINUX
120 #define get_platform_string() "LINUX"
121 #elif defined FREEBSD
122 #define get_platform_string() "FREEBSD"
123 #elif defined WIN32
124 #define get_platform_string() "WIN32"
125 #elif defined INTERIX
126 #define get_platform_string() "INTERIX"
127 #else
128 #error Platform was not set.
129 #endif
130
131 /** structure for describing TTCN-3 and ASN.1 modules */
132 struct module_struct {
133 char *dir_name; /* directory of the TTCN-3 or ASN.1 file, it is NULL if the
134 file is in the current working directory */
135 char *file_name; /* name of the TTCN-3 or ASN.1 file */
136 char *module_name; /* name of the TTCN-3 or ASN.1 module */
137 boolean is_regular; /* indicates whether the name of the source file follows
138 the default naming convention */
139 };
140
141 /** structure for describing test ports and other C/C++ modules */
142 struct user_struct {
143 char *dir_name; /* directory of the C/C++ source files, it is NULL if the
144 files are in the current working directory */
145 char *file_prefix; /* the common prefix of the header and source file */
146 char *header_name; /* name of the C/C++ header file, which has .hh or .h or .hpp
147 suffix, it is NULL if there is no header file */
148 char *source_name; /* name of the C/C++ source file, which has .cc or .c or .cpp
149 suffix, it is NULL if there is no source file */
150 boolean has_hh_suffix; /* indicates whether the header file is present and
151 has .hh or .hpp suffix */
152 boolean has_cc_suffix; /* indicates whether the source file is present and
153 has .cc or .cpp suffix */
154 };
155
156 /** structure for directories that pre-compiled files are taken from */
157 struct base_dir_struct {
158 const char *dir_name; /* name of the directory */
159 boolean has_modules; /* indicates whether there are TTCN-3/ASN.1 modules in
160 the directory (it is set to FALSE if dir_name
161 contains user C/C++ files only */
162 };
163
164 /** data structure that describes the information needed for the Makefile */
165 struct makefile_struct {
166 size_t nTTCN3Modules;
167 struct module_struct *TTCN3Modules;
168
169 boolean preprocess;
170 size_t nTTCN3PPModules;
171 struct module_struct *TTCN3PPModules;
172
173 boolean TTCN3ModulesRegular;
174 boolean BaseTTCN3ModulesRegular;
175 size_t nTTCN3IncludeFiles;
176 char **TTCN3IncludeFiles;
177
178 size_t nASN1Modules;
179 struct module_struct *ASN1Modules;
180 boolean ASN1ModulesRegular;
181 boolean BaseASN1ModulesRegular;
182
183 size_t nUserFiles;
184 struct user_struct *UserFiles;
185 boolean UserHeadersRegular;
186 boolean UserSourcesRegular;
187 boolean BaseUserHeadersRegular;
188 boolean BaseUserSourcesRegular;
189
190 size_t nOtherFiles;
191 char **OtherFiles;
192
193 boolean central_storage;
194 size_t nBaseDirs;
195 struct base_dir_struct *BaseDirs;
196 char *working_dir;
197 boolean gnu_make;
198 boolean single_mode;
199 char *output_file;
200 char *ets_name;
201 boolean force_overwrite;
202 boolean use_runtime_2;
203 boolean dynamic;
204 boolean gcc_dep;
205 char *code_splitting_mode;
206 boolean coverage;
207 char *tcov_file_name;
208 boolean library;
209 struct string_list* sub_project_dirs; /* not owned */
210 struct string_list* ttcn3_prep_includes; /* not owned */
211 struct string_list* ttcn3_prep_defines; /* not owned */
212 struct string_list* prep_includes; /* not owned */
213 struct string_list* prep_defines; /* not owned */
214 boolean codesplittpd;
215 boolean quietly;
216 boolean disablesubtypecheck;
217 const char *cxxcompiler;
218 const char *optlevel;
219 const char *optflags;
220 boolean disableber;
221 boolean disableraw;
222 boolean disabletext;
223 boolean disablexer;
224 boolean disablejson;
225 boolean forcexerinasn;
226 boolean defaultasomit;
227 boolean gccmsgformat;
228 boolean linenumbersonlymsg;
229 boolean includesourceinfo;
230 boolean addsourcelineinfo;
231 boolean suppresswarnings;
232 boolean outparamboundness;
233 struct string_list* solspeclibraries; /* not owned */
234 struct string_list* sol8speclibraries; /* not owned */
235 struct string_list* linuxspeclibraries; /* not owned */
236 struct string_list* freebsdspeclibraries; /* not owned */
237 struct string_list* win32speclibraries; /* not owned */
238 const char *ttcn3preprocessor;
239 struct string_list* linkerlibraries; /* not owned */
240 struct string_list* additionalObjects; /* not owned */
241 struct string_list* linkerlibsearchpath; /* not owned */
242 char* generatorCommandOutput; /* not owned */
243 struct string2_list* target_placement_list; /* not owned */
244 };
245
246 /** Initializes structure \a makefile with empty lists and default settings. */
247 static void init_makefile_struct(struct makefile_struct *makefile)
248 {
249 makefile->nTTCN3Modules = 0;
250 makefile->TTCN3Modules = NULL;
251 makefile->preprocess = FALSE;
252 makefile->nTTCN3PPModules = 0;
253 makefile->TTCN3PPModules = NULL;
254 makefile->TTCN3ModulesRegular = TRUE;
255 makefile->BaseTTCN3ModulesRegular = TRUE;
256 makefile->nTTCN3IncludeFiles = 0;
257 makefile->TTCN3IncludeFiles = NULL;
258 makefile->nASN1Modules = 0;
259 makefile->ASN1Modules = NULL;
260 makefile->ASN1ModulesRegular = TRUE;
261 makefile->BaseASN1ModulesRegular = TRUE;
262 makefile->nUserFiles = 0;
263 makefile->UserFiles = NULL;
264 makefile->UserHeadersRegular = TRUE;
265 makefile->UserSourcesRegular = TRUE;
266 makefile->BaseUserHeadersRegular = TRUE;
267 makefile->BaseUserSourcesRegular = TRUE;
268 makefile->nOtherFiles = 0;
269 makefile->OtherFiles = NULL;
270 makefile->central_storage = FALSE;
271 makefile->nBaseDirs = 0;
272 makefile->BaseDirs = NULL;
273 makefile->working_dir = get_working_dir();
274 makefile->gnu_make = FALSE;
275 makefile->single_mode = FALSE;
276 makefile->ets_name = NULL;
277 makefile->output_file = NULL;
278 makefile->force_overwrite = FALSE;
279 makefile->use_runtime_2 = FALSE;
280 makefile->dynamic = FALSE;
281 makefile->gcc_dep = FALSE;
282 makefile->code_splitting_mode = NULL;
283 makefile->coverage = FALSE;
284 makefile->tcov_file_name = NULL;
285 makefile->library = FALSE;
286 makefile->sub_project_dirs = NULL;
287 makefile->ttcn3_prep_includes = NULL;
288 makefile->prep_includes = NULL;
289 makefile->prep_defines = NULL;
290 makefile->outparamboundness = FALSE;
291 makefile->solspeclibraries = NULL;
292 makefile->sol8speclibraries = NULL;
293 makefile->linuxspeclibraries = NULL;
294 makefile->freebsdspeclibraries = NULL;
295 makefile->win32speclibraries = NULL;
296 makefile->linkerlibraries = NULL;
297 makefile->additionalObjects = NULL;
298 makefile->linkerlibsearchpath = NULL;
299 makefile->generatorCommandOutput = NULL;
300 makefile->target_placement_list = NULL;
301 }
302
303 /** Deallocates all memory associated with structure \a makefile. */
304 static void free_makefile_struct(const struct makefile_struct *makefile)
305 {
306 size_t i;
307 for (i = 0; i < makefile->nTTCN3Modules; i++) {
308 Free(makefile->TTCN3Modules[i].dir_name);
309 Free(makefile->TTCN3Modules[i].file_name);
310 Free(makefile->TTCN3Modules[i].module_name);
311 }
312 Free(makefile->TTCN3Modules);
313 for (i = 0; i < makefile->nTTCN3PPModules; i++) {
314 Free(makefile->TTCN3PPModules[i].dir_name);
315 Free(makefile->TTCN3PPModules[i].file_name);
316 Free(makefile->TTCN3PPModules[i].module_name);
317 }
318 Free(makefile->TTCN3PPModules);
319 for (i = 0; i < makefile->nTTCN3IncludeFiles; i++)
320 Free(makefile->TTCN3IncludeFiles[i]);
321 Free(makefile->TTCN3IncludeFiles);
322 for (i = 0; i < makefile->nASN1Modules; i++) {
323 Free(makefile->ASN1Modules[i].dir_name);
324 Free(makefile->ASN1Modules[i].file_name);
325 Free(makefile->ASN1Modules[i].module_name);
326 }
327 Free(makefile->ASN1Modules);
328 for (i = 0; i < makefile->nUserFiles; i++) {
329 Free(makefile->UserFiles[i].dir_name);
330 Free(makefile->UserFiles[i].file_prefix);
331 Free(makefile->UserFiles[i].header_name);
332 Free(makefile->UserFiles[i].source_name);
333 }
334 Free(makefile->UserFiles);
335 for (i = 0; i < makefile->nOtherFiles; i++) Free(makefile->OtherFiles[i]);
336 Free(makefile->OtherFiles);
337 Free(makefile->BaseDirs);
338 Free(makefile->working_dir);
339 Free(makefile->ets_name);
340 Free(makefile->output_file);
341 Free(makefile->code_splitting_mode);
342 Free(makefile->tcov_file_name);
343 }
344
345 /** Displays the contents of structure \a makefile as debug messages. */
346 static void dump_makefile_struct(const struct makefile_struct *makefile,
347 unsigned level)
348 {
349 size_t i;
350 DEBUG(level, "Data used for Makefile generation:");
351 DEBUG(level + 1, "TTCN-3 modules: (%u pcs.)", makefile->nTTCN3Modules);
352 for (i = 0; i < makefile->nTTCN3Modules; i++) {
353 const struct module_struct *module = makefile->TTCN3Modules + i;
354 DEBUG(level + 2, "Module name: %s", module->module_name);
355 if (module->dir_name != NULL)
356 DEBUG(level + 3, "Directory: %s", module->dir_name);
357 DEBUG(level + 3, "File name: %s", module->file_name);
358 DEBUG(level + 3, "Follows the naming convention: %s",
359 module->is_regular ? "yes" : "no");
360 }
361 DEBUG(level + 1, "TTCN-3 preprocessing: %s",
362 makefile->preprocess ? "yes" : "no");
363 if (makefile->preprocess) {
364 DEBUG(level + 1, "TTCN-3 modules to be preprocessed: (%u pcs.)",
365 makefile->nTTCN3PPModules);
366 for (i = 0; i < makefile->nTTCN3PPModules; i++) {
367 const struct module_struct *module = makefile->TTCN3PPModules + i;
368 DEBUG(level + 2, "Module name: %s", module->module_name);
369 if (module->dir_name != NULL)
370 DEBUG(level + 3, "Directory: %s", module->dir_name);
371 DEBUG(level + 3, "File name: %s", module->file_name);
372 DEBUG(level + 3, "Follows the naming convention: %s",
373 module->is_regular ? "yes" : "no");
374 }
375 DEBUG(level + 1, "TTCN-3 include files: (%u pcs.)",
376 makefile->nTTCN3IncludeFiles);
377 for (i = 0; i < makefile->nTTCN3IncludeFiles; i++)
378 DEBUG(level + 2, "File name: %s", makefile->TTCN3IncludeFiles[i]);
379 }
380 DEBUG(level + 1, "All local TTCN-3 modules follow the naming convention: %s",
381 makefile->TTCN3ModulesRegular ? "yes" : "no");
382 if (makefile->central_storage) DEBUG(level + 1, "All TTCN-3 modules from other "
383 "directories follow the naming convention: %s",
384 makefile->BaseTTCN3ModulesRegular ? "yes" : "no");
385 DEBUG(level + 1, "ASN.1 modules: (%u pcs.)", makefile->nASN1Modules);
386 for (i = 0; i < makefile->nASN1Modules; i++) {
387 const struct module_struct *module = makefile->ASN1Modules + i;
388 DEBUG(level + 2, "Module name: %s", module->module_name);
389 if (module->dir_name != NULL)
390 DEBUG(level + 3, "Directory: %s", module->dir_name);
391 DEBUG(level + 3, "File name: %s", module->file_name);
392 DEBUG(level + 3, "Follows the naming convention: %s",
393 module->is_regular ? "yes" : "no");
394 }
395 DEBUG(level + 1, "All local ASN.1 modules follow the naming convention: %s",
396 makefile->ASN1ModulesRegular ? "yes" : "no");
397 if (makefile->central_storage) DEBUG(level + 1, "All ASN.1 modules from other "
398 "directories follow the naming convention: %s",
399 makefile->BaseASN1ModulesRegular ? "yes" : "no");
400 DEBUG(level + 1, "User C/C++ modules: (%u pcs.)", makefile->nUserFiles);
401 for (i = 0; i < makefile->nUserFiles; i++) {
402 const struct user_struct *user = makefile->UserFiles + i;
403 DEBUG(level + 2, "File prefix: %s", user->file_prefix);
404 if (user->dir_name != NULL)
405 DEBUG(level + 3, "Directory: %s", user->dir_name);
406 if (user->header_name != NULL) {
407 DEBUG(level + 3, "Header file: %s", user->header_name);
408 DEBUG(level + 3, "Header file has .hh or .hpp suffix: %s",
409 user->has_hh_suffix ? "yes" : "no");
410 }
411 if (user->source_name != NULL) {
412 DEBUG(level + 3, "Source file: %s", user->source_name);
413 DEBUG(level + 3, "Source file has .cc or .cpp suffix: %s",
414 user->has_cc_suffix ? "yes" : "no");
415 DEBUG(level + 3, "Object file: %s.o", user->file_prefix);
416 }
417 }
418 DEBUG(level + 1, "All local C/C++ header files follow the naming "
419 "convention: %s", makefile->UserHeadersRegular ? "yes" : "no");
420 DEBUG(level + 1, "All local C/C++ source files follow the naming "
421 "convention: %s", makefile->UserSourcesRegular ? "yes" : "no");
422 if (makefile->central_storage) {
423 DEBUG(level + 1, "All C/C++ header files from other directories follow the "
424 "naming convention: %s", makefile->BaseUserHeadersRegular ? "yes" : "no");
425 DEBUG(level + 1, "All C/C++ source files from other directories follow the "
426 "naming convention: %s", makefile->BaseUserSourcesRegular ? "yes" : "no");
427 }
428 DEBUG(level + 1, "Other files: (%u pcs.)", makefile->nOtherFiles);
429 for (i = 0; i < makefile->nOtherFiles; i++)
430 DEBUG(level + 2, "File name: %s", makefile->OtherFiles[i]);
431 DEBUG(level + 1, "Use pre-compiled files from central storage: %s",
432 makefile->central_storage ? "yes" : "no");
433 if (makefile->central_storage) {
434 DEBUG(level + 1, "Directories of pre-compiled files: (%u pcs.)",
435 makefile->nBaseDirs);
436 for (i = 0; i < makefile->nBaseDirs; i++) {
437 const struct base_dir_struct *base_dir = makefile->BaseDirs + i;
438 DEBUG(level + 2, "Directory: %s", base_dir->dir_name);
439 DEBUG(level + 3, "Has TTCN-3/ASN.1 modules: %s",
440 base_dir->has_modules ? "yes" : "no");
441 }
442 }
443 DEBUG(level + 1, "Working directory: %s",
444 makefile->working_dir != NULL ? makefile->working_dir : "<unknown>");
445 DEBUG(level + 1, "GNU make: %s", makefile->gnu_make ? "yes" : "no");
446 DEBUG(level + 1, "Execution mode: %s",
447 makefile->single_mode ? "single" : "parallel");
448 DEBUG(level + 1, "Name of executable: %s",
449 makefile->ets_name != NULL ? makefile->ets_name : "<unknown>");
450 DEBUG(level + 1, "Output file: %s",
451 makefile->output_file != NULL ? makefile->output_file : "<unknown>");
452 DEBUG(level + 1, "Force overwrite: %s",
453 makefile->force_overwrite ? "yes" : "no");
454 DEBUG(level + 1, "Use function test runtime: %s",
455 makefile->use_runtime_2 ? "yes" : "no");
456 DEBUG(level + 1, "Use dynamic linking: %s",
457 makefile->dynamic ? "yes" : "no");
458 DEBUG(level + 1, "Code splitting mode: %s",
459 makefile->code_splitting_mode != NULL ?
460 makefile->code_splitting_mode : "<unknown>");
461 DEBUG(level + 1, "Code coverage file: %s",
462 makefile->tcov_file_name != NULL ?
463 makefile->tcov_file_name : "<unknown>");
464 #ifdef COVERAGE_BUILD
465 DEBUG(level + 1, "Enable coverage: %s", makefile->coverage ? "yes" : "no");
466 #endif
467 }
468
469 /** Returns the name of an existing file that is related to command line
470 * argument \a argument. Tries the given list of suffixes. NULL pointer is
471 * returned if no file was found. The returned string shall be deallocated
472 * by the caller. */
473 static char *get_file_name_for_argument(const char *argument)
474 {
475 static const char * const suffix_list[] = {
476 "", ".ttcnpp", ".ttcnin", ".ttcn", ".ttcn3", ".3mp", ".asn", ".asn1",
477 ".cc", ".c", ".cpp", ".hh", ".h",".hpp", ".cfg", ".prj", NULL
478 };
479 const char * const *suffix_ptr;
480 for (suffix_ptr = suffix_list; *suffix_ptr != NULL; suffix_ptr++) {
481 char *file_name = mputstr(mcopystr(argument), *suffix_ptr);
482 if (get_path_status(file_name) == PS_FILE) return file_name;
483 Free(file_name);
484 }
485 return NULL;
486 }
487
488 /** Converts \a path_name to an absolute directory using \a working_dir.
489 * NULL pointer is returned if \a path_name does not contain a directory or
490 * the resulting absolute directory is identical to \a working_dir.
491 * The returned string shall be deallocated by the caller. */
492 static char *get_dir_name(const char *path_name, const char *working_dir)
493 {
494 char *dir_name = get_dir_from_path(path_name);
495 if (dir_name != NULL) {
496 char *absolute_dir = get_absolute_dir(dir_name, working_dir);
497 Free(dir_name);
498 if (absolute_dir == NULL || working_dir == NULL) {
499 /* an error occurred */
500 return NULL;
501 } else if (!strcmp(absolute_dir, working_dir)) {
502 /* the directory is identical to the working dir */
503 Free(absolute_dir);
504 return NULL;
505 } else return absolute_dir;
506 } else return NULL;
507 }
508
509 /** Returns whether \a dirname1 and \a dirname2 contain the same (canonized
510 * absolute) directories. NULL pointer is handled in a special way: it is
511 * identical only to itself. */
512 static boolean is_same_directory(const char *dirname1, const char *dirname2)
513 {
514 if (dirname1 == NULL) {
515 if (dirname2 == NULL) return TRUE;
516 else return FALSE;
517 } else {
518 if (dirname2 == NULL) return FALSE;
519 else if (strcmp(dirname1, dirname2)) return FALSE;
520 else return TRUE;
521 }
522 }
523
524 /** Returns whether the file \a filename1 in directory \a dirname1 is identical
525 * to file \a filename2 in directory \a dirname2. Only the directory names can
526 * be NULL. */
527 static boolean is_same_file(const char *dirname1, const char *filename1,
528 const char *dirname2, const char *filename2)
529 {
530 /* first examine the file names for efficiency reasons */
531 if (strcmp(filename1, filename2)) return FALSE;
532 else return is_same_directory(dirname1, dirname2);
533 }
534
535 /** Determines whether the TTCN-3 or ASN.1 module identifiers \a module1 and
536 * \a module2 are the same. Characters '-' and '_' in module names are not
537 * distinguished. */
538 static boolean is_same_module(const char *module1, const char *module2)
539 {
540 size_t i;
541 for (i = 0; ; i++) {
542 switch (module1[i]) {
543 case '\0':
544 if (module2[i] == '\0') return TRUE;
545 else return FALSE;
546 case '-':
547 case '_':
548 if (module2[i] != '-' && module2[i] != '_') return FALSE;
549 break;
550 default:
551 if (module1[i] != module2[i]) return FALSE;
552 break;
553 }
554 }
555 return FALSE; /* to avoid warnings */
556 }
557
558 /** Determines the suffix (i.e. the character sequence following the last dot)
559 * of file or path name \a file_name. NULL pointer is returned if \a file_name
560 * does not contain any dot character or the last character of it is a dot.
561 * The suffix is not copied, the returned pointer points to the tail of
562 * \a file_name. */
563 static const char *get_suffix(const char *file_name)
564 {
565 size_t last_dot = (size_t)-1;
566 size_t i;
567 for (i = 0; file_name[i] != '\0'; i++)
568 if (file_name[i] == '.') last_dot = i;
569 if (last_dot == (size_t)-1 || file_name[last_dot + 1] == '\0') return NULL;
570 else return file_name + last_dot + 1;
571 }
572
573 /** Truncates the suffix (i.e. the last dot and the characters following it)
574 * from \a file_name and returns a copy of the prefix of \a file_name.
575 * If \a file_name does not have a suffix an exact copy of it is returned.
576 * The returned string shall be deallocated by the caller. */
577 static char *cut_suffix(const char *file_name)
578 {
579 char *ret_val;
580 size_t last_dot = (size_t)-1;
581 size_t i;
582 for (i = 0; file_name[i] != '\0'; i++)
583 if (file_name[i] == '.') last_dot = i;
584 ret_val = mcopystr(file_name);
585 if (last_dot != (size_t)-1) ret_val = mtruncstr(ret_val, last_dot);
586 return ret_val;
587 }
588
589 /** Determines the name of the preprocessed file from \a file_name.
590 * It is assumed that \a file_name has ttcnpp suffix.
591 * The returned string shall be deallocated by the caller. */
592 static char *get_preprocessed_file_name(const char *file_name)
593 {
594 char *ret_val = cut_suffix(file_name);
595 ret_val = mputstr(ret_val, ".ttcn");
596 return ret_val;
597 }
598
599 /** Check if any of the preprocessed ttcn file names with the preprocessed
600 * (TTCN-3) suffix is equal to any other file given in the \a makefile */
601 static void check_preprocessed_filename_collision(
602 struct makefile_struct *makefile)
603 {
604 size_t i;
605 if (makefile->nTTCN3PPModules == 0) {
606 WARNING("TTCN-3 preprocessing (option `-p') is enabled, but no TTCN-3 "
607 "files to be preprocessed were given for the Makefile.");
608 }
609 for (i = 0; i < makefile->nTTCN3PPModules; i++) {
610 const struct module_struct *pp_module = makefile->TTCN3PPModules + i;
611 /* name of the intermediate preprocessed file */
612 char *preprocessed_name = get_preprocessed_file_name(pp_module->file_name);
613 size_t j;
614 for (j = 0; j < makefile->nTTCN3Modules; j++) {
615 struct module_struct *module = makefile->TTCN3Modules + j;
616 if (is_same_file(pp_module->dir_name, preprocessed_name,
617 module->dir_name, module->file_name)) {
618 if (is_same_module(pp_module->module_name, module->module_name)) {
619 /* same file with the same module */
620 char *pp_pathname = compose_path_name(pp_module->dir_name,
621 pp_module->file_name);
622 char *m_pathname = compose_path_name(module->dir_name,
623 module->file_name);
624 WARNING("File `%s' containing TTCN-3 module `%s' is generated by "
625 "the preprocessor from `%s'. Removing the file from the list of "
626 "normal TTCN-3 modules.", m_pathname, module->module_name,
627 pp_pathname);
628 Free(pp_pathname);
629 Free(m_pathname);
630 Free(module->dir_name);
631 Free(module->file_name);
632 Free(module->module_name);
633 makefile->nTTCN3Modules--;
634 memmove(module, module + 1, (makefile->nTTCN3Modules - j) *
635 sizeof(*makefile->TTCN3Modules));
636 makefile->TTCN3Modules =
637 (struct module_struct*)Realloc(makefile->TTCN3Modules,
638 makefile->nTTCN3Modules * sizeof(*makefile->TTCN3Modules));
639 } else {
640 /* same file with different module */
641 char *pp_pathname = compose_path_name(pp_module->dir_name,
642 pp_module->file_name);
643 char *m_pathname = compose_path_name(module->dir_name,
644 module->file_name);
645 ERROR("Preprocessed intermediate file of `%s' (module `%s') clashes "
646 "with file `%s' containing TTCN-3 module `%s'.", pp_pathname,
647 pp_module->module_name, m_pathname, module->module_name);
648 Free(pp_pathname);
649 Free(m_pathname);
650 }
651 } else if (is_same_module(pp_module->module_name, module->module_name)) {
652 /* different file with the same module */
653 char *pp_pathname = compose_path_name(pp_module->dir_name,
654 pp_module->file_name);
655 char *m_pathname = compose_path_name(module->dir_name,
656 module->file_name);
657 ERROR("Both files `%s' and `%s' contain TTCN-3 module `%s'.",
658 pp_pathname, m_pathname, pp_module->module_name);
659 Free(pp_pathname);
660 Free(m_pathname);
661 }
662 }
663 for (j = 0; j < makefile->nASN1Modules; j++) {
664 struct module_struct *module = makefile->ASN1Modules + j;
665 if (is_same_file(pp_module->dir_name, preprocessed_name,
666 module->dir_name, module->file_name)) {
667 char *pp_pathname = compose_path_name(pp_module->dir_name,
668 pp_module->file_name);
669 char *m_pathname = compose_path_name(module->dir_name,
670 module->file_name);
671 ERROR("Preprocessed intermediate file of `%s' (module `%s') clashes "
672 "with file `%s' containing ASN.1 module `%s'.", pp_pathname,
673 pp_module->module_name, m_pathname, module->module_name);
674 Free(pp_pathname);
675 Free(m_pathname);
676 }
677 }
678 for (j = 0; j < makefile->nOtherFiles; j++) {
679 char *dir_name = get_dir_name(makefile->OtherFiles[j],
680 makefile->working_dir);
681 char *file_name = get_file_from_path(makefile->OtherFiles[j]);
682 if (is_same_file(pp_module->dir_name, preprocessed_name, dir_name,
683 file_name)) {
684 char *pp_pathname = compose_path_name(pp_module->dir_name,
685 pp_module->file_name);
686 ERROR("Preprocessed intermediate file of `%s' (module `%s') clashes "
687 "with other file `%s'.", pp_pathname, pp_module->module_name,
688 makefile->OtherFiles[j]);
689 Free(pp_pathname);
690 }
691 Free(dir_name);
692 Free(file_name);
693 }
694 Free(preprocessed_name);
695 }
696 }
697
698 /** Checks the name clash between existing module \a module and newly added
699 * module with parameters \a path_name, \a dir_name, \a file_name,
700 * \a module_name. Both the existing and the new module shall be of the same
701 * kind, parameter \a kind shall contain the respective string (either "ASN.1"
702 * or "TTCN-3"). If a clash is found the parameters of the new module except
703 * \a path_name are deallocated and TRUE is returned. Otherwise FALSE is
704 * returned. */
705 static boolean check_module_clash_same(const struct module_struct *module,
706 const char *kind, const char *path_name, char *dir_name, char *file_name,
707 char *module_name)
708 {
709 if (is_same_module(module_name, module->module_name)) {
710 if (is_same_file(dir_name, file_name,
711 module->dir_name, module->file_name)) {
712 /* the same file was given twice: just issue a warning */
713 WARNING("File `%s' was given more than once for the Makefile.",
714 path_name);
715 } else {
716 /* two different files contain the same module: this cannot be
717 * resolved as the generated C++ files will clash */
718 char *path_name1 = compose_path_name(module->dir_name,
719 module->file_name);
720 char *path_name2 = compose_path_name(dir_name, file_name);
721 ERROR("Both files `%s' and `%s' contain %s module `%s'.",
722 path_name1, path_name2, kind, module_name);
723 Free(path_name1);
724 Free(path_name2);
725 }
726 Free(file_name);
727 Free(dir_name);
728 Free(module_name);
729 return TRUE;
730 } else return FALSE;
731 }
732
733 /** Checks the name clash between existing module \a module and newly added
734 * module with parameters \a dir_name, \a file_name, \a module_name. The two
735 * modules shall be of different kinds (one is ASN.1, the other is TTCN-3).
736 * Parameters \a kind1 and \a kind2 shall contain the respective strings. If a
737 * clash is found the parameters of the new module are deallocated and TRUE is
738 * returned. Otherwise FALSE is returned. */
739 static boolean check_module_clash_different(const struct module_struct *module,
740 const char *kind1, char *dir_name, char *file_name, char *module_name,
741 const char *kind2)
742 {
743 if (is_same_module(module_name, module->module_name)) {
744 /* two different files contain the same module: this cannot be resolved
745 * as the generated C++ files will clash */
746 char *path_name1 = compose_path_name(module->dir_name, module->file_name);
747 char *path_name2 = compose_path_name(dir_name, file_name);
748 ERROR("File `%s' containing %s module `%s' and file `%s' containing "
749 "%s module `%s' cannot be used together in the same Makefile.",
750 path_name1, kind1, module->module_name, path_name2, kind2, module_name);
751 Free(path_name1);
752 Free(path_name2);
753 Free(file_name);
754 Free(dir_name);
755 Free(module_name);
756 return TRUE;
757 } else return FALSE;
758 }
759
760 /** Adds a TTCN-3 module to Makefile descriptor structure \a makefile.
761 * The name of the TTCN-3 source file is \a path_name, the module identifier
762 * is \a module_name. It is checked whether a file or module with the same name
763 * already exists in \a makefile and an appropriate warning or error is
764 * reported. */
765 static void add_ttcn3_module(struct makefile_struct *makefile,
766 const char *path_name, char *module_name)
767 {
768 struct module_struct *module;
769 char *dir_name = get_dir_name(path_name, makefile->working_dir);
770 char *file_name = get_file_from_path(path_name);
771 const char *suffix = get_suffix(file_name);
772 size_t i;
773 boolean is_preprocessed = FALSE;
774
775 if (suffix != NULL) {
776 if (!strcmp(suffix, "ttcnpp")) {
777 if (makefile->preprocess) is_preprocessed = TRUE;
778 else WARNING("The suffix of TTCN-3 file `%s' indicates that it should be "
779 "preprocessed, but TTCN-3 preprocessing is not enabled. The file "
780 "will be added to the list of normal TTCN-3 modules in the Makefile.",
781 path_name);
782 } else if (!strcmp(suffix, "ttcnin")) {
783 WARNING("The suffix of file `%s' indicates that it should be a "
784 "preprocessor include file, but it contains a TTCN-3 module named `%s'. "
785 "The file will be added to the list of normal TTCN-3 modules in the "
786 "Makefile.", path_name, module_name);
787 }
788 }
789
790 for (i = 0; i < makefile->nASN1Modules; i++) {
791 if (check_module_clash_different(makefile->ASN1Modules + i, "ASN.1",
792 dir_name, file_name, module_name, "TTCN-3")) return;
793 }
794 /* never entered if suffix is NULL */
795 if (is_preprocessed) {
796 char *file_prefix;
797 for (i = 0; i < makefile->nTTCN3PPModules; i++) {
798 if (check_module_clash_same(makefile->TTCN3PPModules + i, "TTCN-3",
799 path_name, dir_name, file_name, module_name)) return;
800 }
801 /* clashes with normal TTCN-3 modules will be checked (and maybe resolved)
802 * in \a check_preprocessed_filename_collision() */
803 /* add it to the list of TTCN-3 modules to be preprocessed */
804 makefile->TTCN3PPModules = (struct module_struct*)
805 Realloc(makefile->TTCN3PPModules,
806 (makefile->nTTCN3PPModules + 1) * sizeof(*makefile->TTCN3PPModules));
807 module = makefile->TTCN3PPModules + makefile->nTTCN3PPModules;
808 makefile->nTTCN3PPModules++;
809 module->dir_name = dir_name;
810 module->file_name = file_name;
811 module->module_name = module_name;
812 file_prefix = cut_suffix(file_name);
813 if (!strcmp(file_prefix, module_name)) module->is_regular = TRUE;
814 else module->is_regular = FALSE;
815 Free(file_prefix);
816 } else {
817 /* the file is not preprocessed */
818 for (i = 0; i < makefile->nTTCN3Modules; i++) {
819 if (check_module_clash_same(makefile->TTCN3Modules + i, "TTCN-3",
820 path_name, dir_name, file_name, module_name)) return;
821 }
822 /* clashes with preprocessed TTCN-3 modules will be checked (and maybe
823 * resolved) in \a check_preprocessed_filename_collision() */
824 /* add it to the list of normal TTCN-3 modules */
825 makefile->TTCN3Modules = (struct module_struct*)
826 Realloc(makefile->TTCN3Modules,
827 (makefile->nTTCN3Modules + 1) * sizeof(*makefile->TTCN3Modules));
828 module = makefile->TTCN3Modules + makefile->nTTCN3Modules;
829 makefile->nTTCN3Modules++;
830 module->dir_name = dir_name;
831 module->file_name = file_name;
832 module->module_name = module_name;
833 if (suffix != NULL && !strcmp(suffix, "ttcn")) {
834 char *file_prefix = cut_suffix(file_name);
835 if (!strcmp(file_prefix, module_name)) module->is_regular = TRUE;
836 else module->is_regular = FALSE;
837 Free(file_prefix);
838 } else {
839 module->is_regular = FALSE;
840 }
841 }
842 }
843
844 /** ASN.1 filename shall contain no hyphen */
845 static boolean is_valid_asn1_filename(const char* file_name)
846 {
847 if (0 == strchr(file_name, '-')) {
848 return TRUE;
849 }
850 return FALSE;
851 }
852
853 /** Adds an ASN.1 module to Makefile descriptor structure \a makefile.
854 * The name of the ASN.1 source file is \a path_name, the module identifier
855 * is \a module_name. It is checked whether a file or module with the same name
856 * already exists in \a makefile and an appropriate warning or error is
857 * reported. */
858 static void add_asn1_module(struct makefile_struct *makefile,
859 const char *path_name, char *module_name)
860 {
861 struct module_struct *module;
862 char *dir_name = get_dir_name(path_name, makefile->working_dir);
863 char *file_name = get_file_from_path(path_name);
864 const char *suffix = get_suffix(file_name);
865 size_t i;
866 for (i = 0; i < makefile->nASN1Modules; i++) {
867 if (check_module_clash_same(makefile->ASN1Modules + i, "ASN.1", path_name,
868 dir_name, file_name, module_name)) return;
869 }
870 for (i = 0; i < makefile->nTTCN3Modules; i++) {
871 if (check_module_clash_different(makefile->TTCN3Modules + i, "TTCN-3",
872 dir_name, file_name, module_name, "ASN.1")) return;
873 }
874 if (makefile->preprocess) {
875 for (i = 0; i < makefile->nTTCN3PPModules; i++) {
876 if (check_module_clash_different(makefile->TTCN3PPModules + i, "TTCN-3",
877 dir_name, file_name, module_name, "ASN.1")) return;
878 }
879 }
880 makefile->ASN1Modules = (struct module_struct*)
881 Realloc(makefile->ASN1Modules,
882 (makefile->nASN1Modules + 1) * sizeof(*makefile->ASN1Modules));
883 module = makefile->ASN1Modules + makefile->nASN1Modules;
884 makefile->nASN1Modules++;
885 module->dir_name = dir_name;
886 module->file_name = file_name;
887 module->module_name = module_name;
888 if (suffix != NULL && !strcmp(suffix, "asn")) {
889 char *file_prefix = cut_suffix(file_name);
890 /* replace all '_' with '-' in file name prefix */
891 for (i = 0; file_prefix[i] != '\0'; i++)
892 if (file_prefix[i] == '_') file_prefix[i] = '-';
893 if (!strcmp(file_prefix, module_name)) module->is_regular = TRUE;
894 else module->is_regular = FALSE;
895 Free(file_prefix);
896 } else {
897 module->is_regular = FALSE;
898 }
899 }
900
901 /** Adds the file named \a path_name to the list of files pointed by \a list_ptr
902 * and \a list_size. The suffix or contents of \a path_name are not examined,
903 * only duplicate entries are checked. In case of duplicate entries warning is
904 * reported only if argument \a report_warning is set to TRUE. */
905 static void add_path_to_list(size_t *list_size, char ***list_ptr,
906 const char *path_name, const char *working_dir, boolean report_warning)
907 {
908 size_t i;
909 char *dir_name = get_dir_name(path_name, working_dir);
910 char *file_name = get_file_from_path(path_name);
911 char *canonized_path_name = compose_path_name(dir_name, file_name);
912 Free(dir_name);
913 Free(file_name);
914 for (i = 0; i < *list_size; i++) {
915 if (!strcmp(canonized_path_name, (*list_ptr)[i])) {
916 if (report_warning) WARNING("File `%s' was given more than once for the "
917 "Makefile.", path_name);
918 Free(canonized_path_name);
919 return;
920 }
921 }
922 *list_ptr = (char**)Realloc(*list_ptr, (*list_size + 1) * sizeof(**list_ptr));
923 (*list_ptr)[*list_size] = canonized_path_name;
924 (*list_size)++;
925 }
926
927 /** Adds a C/C++ header or source file or an other file named \a path_name to
928 * Makefile descriptor structure \a makefile. The file is classified based on
929 * its suffix and not by content. If the file clashes with existing files or
930 * modules the appropriate warning or error is generated. */
931 static void add_user_file(struct makefile_struct *makefile,
932 const char *path_name)
933 {
934 const char *suffix = get_suffix(path_name);
935 if (suffix != NULL) {
936 if (!strcmp(suffix, "ttcn") || !strcmp(suffix, "ttcn3") ||
937 !strcmp(suffix, "3mp") || !strcmp(suffix, "ttcnpp")) {
938 /* The file content was already checked. Since it doesn't look like
939 * a valid TTCN-3 file, these suffixes are suspect */
940 WARNING("File `%s' does not contain a valid TTCN-3 module. "
941 "It will be added to the Makefile as other file.", path_name);
942 } else if (!strcmp(suffix, "ttcnin")) {
943 /* this is a TTCN-3 include file */
944 if (makefile->preprocess) {
945 add_path_to_list(&makefile->nTTCN3IncludeFiles,
946 &makefile->TTCN3IncludeFiles, path_name, makefile->working_dir, TRUE);
947 return;
948 } else {
949 WARNING("The suffix of file `%s' indicates that it is a TTCN-3 "
950 "include file, but TTCN-3 preprocessing is not enabled. The file "
951 "will be added to the Makefile as other file.", path_name);
952 }
953 } else if (!strcmp(suffix, "asn") || !strcmp(suffix, "asn1")) {
954 /* The file content was already checked. Since it doesn't look like
955 * a valid ASN.1 file, these suffixes are suspect */
956 WARNING("File `%s' does not contain a valid ASN.1 module. "
957 "It will be added to the Makefile as other file.", path_name);
958 } else if (!strcmp(suffix, "cc") || !strcmp(suffix, "c") || !strcmp(suffix, "cpp")) {
959 /* this is a source file */
960 char *dir_name = get_dir_name(path_name, makefile->working_dir);
961 char *file_name = get_file_from_path(path_name);
962 char *file_prefix = cut_suffix(file_name);
963 struct user_struct *user;
964 size_t i;
965 for (i = 0; i < makefile->nUserFiles; i++) {
966 user = makefile->UserFiles + i;
967 if (!strcmp(file_prefix, user->file_prefix)) {
968 if (user->source_name != NULL) {
969 /* the source file is already present */
970 if (is_same_file(dir_name, file_name,
971 user->dir_name, user->source_name)) {
972 WARNING("File `%s' was given more than once for the Makefile.",
973 path_name);
974 } else {
975 char *path_name1 = compose_path_name(user->dir_name,
976 user->source_name);
977 char *path_name2 = compose_path_name(dir_name, file_name);
978 ERROR("C/C++ source files `%s' and `%s' cannot be used together "
979 "in the same Makefile.", path_name1, path_name2);
980 Free(path_name1);
981 Free(path_name2);
982 }
983 } else {
984 /* a header file with the same prefix is already present */
985 if (is_same_directory(dir_name, user->dir_name)) {
986 user->source_name = file_name;
987 file_name = NULL;
988 if (!strcmp(suffix, "cc") || !strcmp(suffix, "cpp")) user->has_cc_suffix = TRUE;
989 } else {
990 char *path_name1 = compose_path_name(dir_name, file_name);
991 char *path_name2 = compose_path_name(user->dir_name,
992 user->header_name);
993 ERROR("C/C++ source file `%s' cannot be used together with "
994 "header file `%s' in the same Makefile.", path_name1,
995 path_name2);
996 Free(path_name1);
997 Free(path_name2);
998 }
999 }
1000 Free(dir_name);
1001 Free(file_name);
1002 Free(file_prefix);
1003 return;
1004 }
1005 }
1006 makefile->UserFiles = (struct user_struct*)Realloc(makefile->UserFiles,
1007 (makefile->nUserFiles + 1) * sizeof(*makefile->UserFiles));
1008 user = makefile->UserFiles + makefile->nUserFiles;
1009 makefile->nUserFiles++;
1010 user->dir_name = dir_name;
1011 user->file_prefix = file_prefix;
1012 user->header_name = NULL;
1013 user->source_name = file_name;
1014 user->has_hh_suffix = FALSE;
1015 if (!strcmp(suffix, "cc") || !strcmp(suffix, "cpp")) user->has_cc_suffix = TRUE;
1016 else user->has_cc_suffix = FALSE;
1017 return;
1018 } else if (!strcmp(suffix, "hh") || !strcmp(suffix, "h")) {
1019 /* this is a header file */
1020 char *dir_name = get_dir_name(path_name, makefile->working_dir);
1021 char *file_name = get_file_from_path(path_name);
1022 char *file_prefix = cut_suffix(file_name);
1023 struct user_struct *user;
1024 size_t i;
1025 for (i = 0; i < makefile->nUserFiles; i++) {
1026 user = makefile->UserFiles + i;
1027 if (!strcmp(file_prefix, user->file_prefix)) {
1028 if (user->header_name != NULL) {
1029 /* the header file is already present */
1030 if (is_same_file(dir_name, file_name,
1031 user->dir_name, user->header_name)) {
1032 WARNING("File `%s' was given more than once for the Makefile.",
1033 path_name);
1034 } else {
1035 char *path_name1 = compose_path_name(user->dir_name,
1036 user->header_name);
1037 char *path_name2 = compose_path_name(dir_name, file_name);
1038 ERROR("C/C++ header files `%s' and `%s' cannot be used together "
1039 "in the same Makefile.", path_name1, path_name2);
1040 Free(path_name1);
1041 Free(path_name2);
1042 }
1043 } else {
1044 /* a source file with the same prefix is already present */
1045 if (is_same_directory(dir_name, user->dir_name)) {
1046 user->header_name = file_name;
1047 file_name = NULL;
1048 if (!strcmp(suffix, "hh") || !strcmp(suffix, "hpp")) user->has_hh_suffix = TRUE;
1049 } else {
1050 char *path_name1 = compose_path_name(dir_name, file_name);
1051 char *path_name2 = compose_path_name(user->dir_name,
1052 user->source_name);
1053 ERROR("C/C++ header file `%s' cannot be used together with "
1054 "source file `%s' in the same Makefile.", path_name1,
1055 path_name2);
1056 Free(path_name1);
1057 Free(path_name2);
1058 }
1059 }
1060 Free(dir_name);
1061 Free(file_name);
1062 Free(file_prefix);
1063 return;
1064 }
1065 }
1066 makefile->UserFiles = (struct user_struct*)Realloc(makefile->UserFiles,
1067 (makefile->nUserFiles + 1) * sizeof(*makefile->UserFiles));
1068 user = makefile->UserFiles + makefile->nUserFiles;
1069 makefile->nUserFiles++;
1070 user->dir_name = dir_name;
1071 user->file_prefix = file_prefix;
1072 user->header_name = file_name;
1073 user->source_name = NULL;
1074 if (!strcmp(suffix, "hh") || !strcmp(suffix, "hpp")) user->has_hh_suffix = TRUE;
1075 else user->has_hh_suffix = FALSE;
1076 user->has_cc_suffix = FALSE;
1077 return;
1078 }
1079 } /* end if (suffix != NULL) */
1080 /* treat the file as other file if it was not handled yet */
1081 add_path_to_list(&makefile->nOtherFiles, &makefile->OtherFiles, path_name,
1082 makefile->working_dir, TRUE);
1083 }
1084
1085 /** Removes the generated C++ header and/or source files of module \a module
1086 * from Makefile descriptor structure \a makefile. A warning is displayed if
1087 * such file is found. */
1088 static void drop_generated_files(struct makefile_struct *makefile,
1089 const struct module_struct *module)
1090 {
1091 char *module_name = mcopystr(module->module_name);
1092 size_t i;
1093 /* transform all '-' characters in ASN.1 module name to '_' */
1094 for (i = 0; module_name[i] != '\0'; i++)
1095 if (module_name[i] == '-') module_name[i] = '_';
1096 for (i = 0; i < makefile->nUserFiles; i++) {
1097 struct user_struct *user = makefile->UserFiles + i;
1098 if (!strcmp(module_name, user->file_prefix)) {
1099 char *m_pathname = compose_path_name(module->dir_name, module->file_name);
1100 /** Note: if central storage is used the generated C++ files are placed
1101 * into the same directory as the TTCN-3/ASN.1 modules, otherwise the
1102 * files are generated into the working directory. */
1103 boolean is_same_dir = is_same_directory(user->dir_name,
1104 makefile->central_storage ? module->dir_name : NULL);
1105 if (user->header_name != NULL) {
1106 char *u_pathname = compose_path_name(user->dir_name,
1107 user->header_name);
1108 if (is_same_dir && user->has_hh_suffix) {
1109 WARNING("Header file `%s' is generated from module `%s' (file `%s'). "
1110 "Removing it from the list of user files.", u_pathname,
1111 module->module_name, m_pathname);
1112 } else {
1113 ERROR("Header file `%s' cannot be used together with module `%s' "
1114 "(file `%s') in the same Makefile.", u_pathname,
1115 module->module_name, m_pathname);
1116 }
1117 Free(u_pathname);
1118 }
1119 if (user->source_name != NULL) {
1120 char *u_pathname = compose_path_name(user->dir_name,
1121 user->source_name);
1122 if (is_same_dir && user->has_cc_suffix) {
1123 WARNING("Source file `%s' is generated from module `%s' (file "
1124 "`%s'). Removing it from the list of user files.", u_pathname,
1125 module->module_name, m_pathname);
1126 } else {
1127 ERROR("Source file `%s' cannot be used together with module "
1128 "`%s' (file `%s') in the same Makefile.", u_pathname,
1129 module->module_name, m_pathname);
1130 }
1131 Free(u_pathname);
1132 }
1133 Free(m_pathname);
1134 Free(user->dir_name);
1135 Free(user->file_prefix);
1136 Free(user->header_name);
1137 Free(user->source_name);
1138 makefile->nUserFiles--;
1139 memmove(user, user + 1, (makefile->nUserFiles - i) *
1140 sizeof(*makefile->UserFiles));
1141 makefile->UserFiles = (struct user_struct*)Realloc(makefile->UserFiles,
1142 makefile->nUserFiles * sizeof(*makefile->UserFiles));
1143 break;
1144 }
1145 }
1146 Free(module_name);
1147 }
1148
1149 /** Drops all C++ header and source files of the Makefile descriptor structure
1150 * \a makefile that are generated from its TTCN-3 or ASN.1 modules. */
1151 static void filter_out_generated_files(struct makefile_struct *makefile)
1152 {
1153 size_t i;
1154 for (i = 0; i < makefile->nTTCN3Modules; i++) {
1155 drop_generated_files(makefile, makefile->TTCN3Modules + i);
1156 }
1157 if (makefile->preprocess) {
1158 for (i = 0; i < makefile->nTTCN3PPModules; i++) {
1159 drop_generated_files(makefile, makefile->TTCN3PPModules + i);
1160 }
1161 }
1162 for (i = 0; i < makefile->nASN1Modules; i++) {
1163 drop_generated_files(makefile, makefile->ASN1Modules + i);
1164 }
1165 }
1166
1167 /** Completes the list of user C/C++ header and source files in \a makefile.
1168 * If only the source file was given the function looks for the corresponding
1169 * header file or vice versa. */
1170 static void complete_user_files(const struct makefile_struct *makefile)
1171 {
1172 size_t i;
1173 for (i = 0; i < makefile->nUserFiles; i++) {
1174 struct user_struct *user = makefile->UserFiles + i;
1175 if (user->header_name == NULL) {
1176 static const char * const suffix_list[] = { "hh", "h", "hpp", NULL };
1177 const char * const *suffix_ptr;
1178 for (suffix_ptr = suffix_list; *suffix_ptr != NULL; suffix_ptr++) {
1179 char *file_name = mprintf("%s.%s", user->file_prefix, *suffix_ptr);
1180 char *path_name = compose_path_name(user->dir_name, file_name);
1181 if (get_path_status(path_name) == PS_FILE) {
1182 Free(path_name);
1183 user->header_name = file_name;
1184 if (!strcmp(*suffix_ptr, "hh") || !strcmp(*suffix_ptr, "hpp")) user->has_hh_suffix = TRUE;
1185 break;
1186 }
1187 Free(file_name);
1188 Free(path_name);
1189 }
1190 } else if (user->source_name == NULL) {
1191 static const char * const suffix_list[] = { "cc", "c", "cpp", NULL };
1192 const char * const *suffix_ptr;
1193 for (suffix_ptr = suffix_list; *suffix_ptr != NULL; suffix_ptr++) {
1194 char *file_name = mprintf("%s.%s", user->file_prefix, *suffix_ptr);
1195 char *path_name = compose_path_name(user->dir_name, file_name);
1196 if (get_path_status(path_name) == PS_FILE) {
1197 Free(path_name);
1198 user->source_name = file_name;
1199 if (!strcmp(*suffix_ptr, "cc") || !strcmp(*suffix_ptr, "cpp")) user->has_cc_suffix = TRUE;
1200 break;
1201 }
1202 Free(file_name);
1203 Free(path_name);
1204 }
1205 }
1206 }
1207 }
1208
1209 /** Converts the directory name pointed by \a dir_ptr to a relative pathname
1210 * based on \a working_dir. The original directory name is deallocated and
1211 * replaced with a new string. Nothing happens if \a dir_ptr points to NULL. */
1212 static void replace_dir_with_relative(char **dir_ptr, const char *working_dir)
1213 {
1214 if (*dir_ptr != NULL) {
1215 char *rel_dir = get_relative_dir(*dir_ptr, working_dir);
1216 Free(*dir_ptr);
1217 *dir_ptr = rel_dir;
1218 }
1219 }
1220
1221 /** Converts the directory part of path name pointed by \a path_ptr to a relative
1222 * pathname based on \a working_dir. The original path name is deallocated and
1223 * replaced with a new string. */
1224 static void convert_path_to_relative(char **path_ptr, const char *working_dir)
1225 {
1226 char *dir_name = get_dir_name(*path_ptr, working_dir);
1227 if (dir_name != NULL) {
1228 char *file_name = get_file_from_path(*path_ptr);
1229 replace_dir_with_relative(&dir_name, working_dir);
1230 Free(*path_ptr);
1231 *path_ptr = compose_path_name(dir_name, file_name);
1232 Free(file_name);
1233 Free(dir_name);
1234 }
1235 }
1236
1237 /** Converts all directories used by the Makefile descriptor structure
1238 * \a makefile to relative pathnames based on the working directory stored in
1239 * \a makefile. */
1240 static void convert_dirs_to_relative(struct makefile_struct *makefile)
1241 {
1242 size_t i;
1243 for (i = 0; i < makefile->nTTCN3Modules; i++) {
1244 replace_dir_with_relative(&makefile->TTCN3Modules[i].dir_name,
1245 makefile->working_dir);
1246 }
1247 if (makefile->preprocess) {
1248 for (i = 0; i < makefile->nTTCN3PPModules; i++) {
1249 replace_dir_with_relative(&makefile->TTCN3PPModules[i].dir_name,
1250 makefile->working_dir);
1251 }
1252 for (i = 0; i < makefile->nTTCN3IncludeFiles; i++) {
1253 convert_path_to_relative(makefile->TTCN3IncludeFiles + i,
1254 makefile->working_dir);
1255 }
1256 }
1257 for (i = 0; i < makefile->nASN1Modules; i++) {
1258 replace_dir_with_relative(&makefile->ASN1Modules[i].dir_name,
1259 makefile->working_dir);
1260 }
1261 for (i = 0; i < makefile->nUserFiles; i++) {
1262 replace_dir_with_relative(&makefile->UserFiles[i].dir_name,
1263 makefile->working_dir);
1264 }
1265 for (i = 0; i < makefile->nOtherFiles; i++) {
1266 convert_path_to_relative(makefile->OtherFiles + i, makefile->working_dir);
1267 }
1268 if (makefile->ets_name != NULL)
1269 convert_path_to_relative(&makefile->ets_name, makefile->working_dir);
1270 }
1271
1272 /* Returns whether the string \a file_name contains special characters. */
1273 static boolean has_special_chars(const char *file_name)
1274 {
1275 if (file_name != NULL) {
1276 size_t i;
1277 for (i = 0; ; i++) {
1278 int c = (unsigned char)file_name[i];
1279 switch (c) {
1280 case '\0':
1281 return FALSE;
1282 case ' ':
1283 case '*':
1284 case '?':
1285 case '[':
1286 case ']':
1287 case '<':
1288 case '=':
1289 case '>':
1290 case '|':
1291 case '&':
1292 case '$':
1293 case '%':
1294 case '{':
1295 case '}':
1296 case ';':
1297 case ':':
1298 case '(':
1299 case ')':
1300 case '#':
1301 case '!':
1302 case '\'':
1303 case '"':
1304 case '`':
1305 case '\\':
1306 return TRUE;
1307 default:
1308 if (!isascii(c) || !isprint(c)) return TRUE;
1309 break;
1310 }
1311 }
1312 }
1313 return FALSE;
1314 }
1315
1316 /** Checks whether the path name composed of \a dir_name and \a file_name
1317 * contains special characters that are not allowed in the Makefile. Parameter
1318 * \a what contains the description of the corresponding file. */
1319 static void check_special_chars_in_path(const char *dir_name,
1320 const char *file_name, const char *what)
1321 {
1322 if (has_special_chars(dir_name) || has_special_chars(file_name)) {
1323 char *path_name = compose_path_name(dir_name, file_name);
1324 ERROR("The name of %s `%s' contains special characters that cannot be "
1325 "handled properly by the `make' utility and/or the shell.", what,
1326 path_name);
1327 Free(path_name);
1328 }
1329 }
1330
1331 /** Checks whether the directory names or file names that will be used in the
1332 * generated Makefile contain special characters that cannot be handled by the
1333 * "make" utility. */
1334 static void check_special_chars(const struct makefile_struct *makefile)
1335 {
1336 size_t i;
1337 for (i = 0; i < makefile->nTTCN3Modules; i++) {
1338 check_special_chars_in_path(makefile->TTCN3Modules[i].dir_name,
1339 makefile->TTCN3Modules[i].file_name, "TTCN-3 file");
1340 }
1341 if (makefile->preprocess) {
1342 for (i = 0; i < makefile->nTTCN3PPModules; i++) {
1343 check_special_chars_in_path(makefile->TTCN3PPModules[i].dir_name,
1344 makefile->TTCN3PPModules[i].file_name,
1345 "TTCN-3 file to be preprocessed");
1346 }
1347 }
1348 for (i = 0; i < makefile->nASN1Modules; i++) {
1349 check_special_chars_in_path(makefile->ASN1Modules[i].dir_name,
1350 makefile->ASN1Modules[i].file_name, "ASN.1 file");
1351 }
1352 for (i = 0; i < makefile->nUserFiles; i++) {
1353 const struct user_struct *user = makefile->UserFiles + i;
1354 if (user->source_name != NULL)
1355 check_special_chars_in_path(user->dir_name, user->source_name,
1356 "C/C++ source file");
1357 else check_special_chars_in_path(user->dir_name, user->header_name,
1358 "C/C++ header file");
1359 }
1360 for (i = 0; i < makefile->nOtherFiles; i++) {
1361 check_special_chars_in_path(NULL, makefile->OtherFiles[i], "other file");
1362 }
1363 }
1364
1365 /** Adds base directory \a dir_name to Makefile descriptor structure
1366 * \a makefile. Flag \a has_modules indicates whether \a dir_name contains
1367 * TTCN-3 and/or ASN.1 modules. The new directory is ignored if it is already
1368 * added to \a makefile. */
1369 static void add_base_dir(struct makefile_struct *makefile,
1370 const char *dir_name, boolean has_modules)
1371 {
1372 struct base_dir_struct *base_dir;
1373 if (dir_name != NULL) {
1374 size_t i;
1375 for (i = 0; i < makefile->nBaseDirs; i++) {
1376 base_dir = makefile->BaseDirs + i;
1377 if (!strcmp(dir_name, base_dir->dir_name)) {
1378 if (has_modules) base_dir->has_modules = TRUE;
1379 return;
1380 }
1381 }
1382 makefile->BaseDirs = (struct base_dir_struct*)Realloc(makefile->BaseDirs,
1383 (makefile->nBaseDirs + 1) * sizeof(*makefile->BaseDirs));
1384 base_dir = makefile->BaseDirs + makefile->nBaseDirs;
1385 makefile->nBaseDirs++;
1386 base_dir->dir_name = dir_name;
1387 base_dir->has_modules = has_modules;
1388 }
1389 }
1390
1391 /** Collects all directories that are used in the Makefile descriptor structure
1392 * \a makefile in order to use pre-compiled files from them. */
1393 static void collect_base_dirs(struct makefile_struct *makefile)
1394 {
1395 size_t i;
1396 for (i = 0; i < makefile->nTTCN3Modules; i++) {
1397 add_base_dir(makefile, makefile->TTCN3Modules[i].dir_name, TRUE);
1398 }
1399 if (makefile->preprocess) {
1400 for (i = 0; i < makefile->nTTCN3PPModules; i++) {
1401 add_base_dir(makefile, makefile->TTCN3PPModules[i].dir_name, TRUE);
1402 }
1403 }
1404 for (i = 0; i < makefile->nASN1Modules; i++) {
1405 add_base_dir(makefile, makefile->ASN1Modules[i].dir_name, TRUE);
1406 }
1407 for (i = 0; i < makefile->nUserFiles; i++) {
1408 add_base_dir(makefile, makefile->UserFiles[i].dir_name, FALSE);
1409 }
1410 if (makefile->nBaseDirs == 0) {
1411 WARNING("Usage of pre-compiled files from central storage (option `-c') "
1412 "is enabled, but all given files are located in the current working "
1413 "directory.");
1414 }
1415 }
1416
1417 /** Checks whether the TTCN-3, ASN.1 and C++ files follow the default naming
1418 * convention and sets the appropriate flags accordingly. */
1419 static void check_naming_convention(struct makefile_struct *makefile)
1420 {
1421 /* initially set all flags to true */
1422 makefile->TTCN3ModulesRegular = TRUE;
1423 makefile->BaseTTCN3ModulesRegular = TRUE;
1424 makefile->ASN1ModulesRegular = TRUE;
1425 makefile->BaseASN1ModulesRegular = TRUE;
1426 makefile->UserHeadersRegular = TRUE;
1427 makefile->UserSourcesRegular = TRUE;
1428 makefile->BaseUserHeadersRegular = TRUE;
1429 makefile->BaseUserSourcesRegular = TRUE;
1430 if (makefile->central_storage) {
1431 /* this project (Makefile) will use pre-compiled files from other
1432 directories */
1433 size_t i;
1434 for (i = 0; i < makefile->nTTCN3Modules; i++) {
1435 const struct module_struct *module = makefile->TTCN3Modules + i;
1436 if (module->dir_name != NULL) {
1437 if (!module->is_regular) makefile->BaseTTCN3ModulesRegular = FALSE;
1438 } else {
1439 if (!module->is_regular) makefile->TTCN3ModulesRegular = FALSE;
1440 }
1441 if (!makefile->TTCN3ModulesRegular && !makefile->BaseTTCN3ModulesRegular)
1442 break;
1443 }
1444 /* ttcnpp files are ttcn files */
1445 if ((makefile->TTCN3ModulesRegular || makefile->BaseTTCN3ModulesRegular) &&
1446 makefile->preprocess) {
1447 for (i = 0; i < makefile->nTTCN3PPModules; i++) {
1448 const struct module_struct *module = makefile->TTCN3PPModules + i;
1449 if (module->dir_name != NULL) {
1450 if (!module->is_regular) makefile->BaseTTCN3ModulesRegular = FALSE;
1451 } else {
1452 if (!module->is_regular) makefile->TTCN3ModulesRegular = FALSE;
1453 }
1454 if (!makefile->TTCN3ModulesRegular && !makefile->BaseTTCN3ModulesRegular)
1455 break;
1456 }
1457 }
1458 for (i = 0; i < makefile->nASN1Modules; i++) {
1459 const struct module_struct *module = makefile->ASN1Modules + i;
1460 if (module->dir_name != NULL) {
1461 if (!module->is_regular) makefile->BaseASN1ModulesRegular = FALSE;
1462 } else {
1463 if (!module->is_regular) makefile->ASN1ModulesRegular = FALSE;
1464 }
1465 if (!makefile->ASN1ModulesRegular && !makefile->BaseASN1ModulesRegular)
1466 break;
1467 }
1468 for (i = 0; i < makefile->nUserFiles; i++) {
1469 const struct user_struct *user = makefile->UserFiles + i;
1470 if (user->dir_name != NULL) {
1471 if (!user->has_cc_suffix)
1472 makefile->BaseUserSourcesRegular = FALSE;
1473 if (!user->has_cc_suffix || !user->has_hh_suffix)
1474 makefile->BaseUserHeadersRegular = FALSE;
1475 } else {
1476 if (!user->has_cc_suffix)
1477 makefile->UserSourcesRegular = FALSE;
1478 if (!user->has_cc_suffix || !user->has_hh_suffix)
1479 makefile->UserHeadersRegular = FALSE;
1480 }
1481 if (!makefile->UserHeadersRegular && !makefile->UserSourcesRegular &&
1482 !makefile->BaseUserHeadersRegular &&
1483 !makefile->BaseUserSourcesRegular) break;
1484 }
1485 } else {
1486 /* this project (Makefile) will-be stand-alone */
1487 size_t i;
1488 for (i = 0; i < makefile->nTTCN3Modules; i++) {
1489 const struct module_struct *module = makefile->TTCN3Modules + i;
1490 if (!module->is_regular || module->dir_name != NULL) {
1491 makefile->TTCN3ModulesRegular = FALSE;
1492 break;
1493 }
1494 }
1495 if (makefile->TTCN3ModulesRegular && makefile->preprocess) {
1496 for (i = 0; i < makefile->nTTCN3PPModules; i++) {
1497 const struct module_struct *module = makefile->TTCN3PPModules + i;
1498 if (!module->is_regular || module->dir_name != NULL) {
1499 makefile->TTCN3ModulesRegular = FALSE;
1500 break;
1501 }
1502 }
1503 }
1504 for (i = 0; i < makefile->nASN1Modules; i++) {
1505 const struct module_struct *module = makefile->ASN1Modules + i;
1506 if (!module->is_regular || module->dir_name != NULL) {
1507 makefile->ASN1ModulesRegular = FALSE;
1508 break;
1509 }
1510 }
1511 for (i = 0; i < makefile->nUserFiles; i++) {
1512 const struct user_struct *user = makefile->UserFiles + i;
1513 if (!user->has_cc_suffix)
1514 makefile->UserSourcesRegular = FALSE;
1515 if (!user->has_cc_suffix || !user->has_hh_suffix)
1516 makefile->UserHeadersRegular = FALSE;
1517 if (!makefile->UserHeadersRegular && !makefile->UserSourcesRegular)
1518 break;
1519 }
1520 }
1521 }
1522
1523 /** Prints the name of the TTCN-3 or ASN.1 source file that belongs to module
1524 * \a module to file \a fp. */
1525 static void print_file_name(FILE *fp, const struct module_struct *module)
1526 {
1527 char *path_name = compose_path_name(module->dir_name, module->file_name);
1528 fprintf(fp, " %s", path_name);
1529 Free(path_name);
1530 }
1531
1532 /** Prints the name of the preprocessed TTCN-3 source file that belongs to
1533 * module \a module to file \a fp. */
1534 static void print_preprocessed_file_name(FILE *fp,
1535 const struct module_struct *module)
1536 {
1537 char *preprocessed_name = get_preprocessed_file_name(module->file_name);
1538 char *path_name = compose_path_name(module->dir_name, preprocessed_name);
1539 fprintf(fp, " %s", path_name);
1540 Free(path_name);
1541 Free(preprocessed_name);
1542 }
1543
1544 /** Prints the name of the generated header, source or object file of module
1545 * \a module to file \a fp. The name of the directory is added only if
1546 * \a add_directory is TRUE. Parameter \a suffix shall be "hh", "cc", "hpp", "cpp" or "o". */
1547 static void print_generated_file_name(FILE *fp,
1548 const struct module_struct *module, boolean add_directory, const char *suffix)
1549 {
1550 char *file_name = mcopystr(module->module_name);
1551 /* replace '-' with '_' */
1552 size_t i;
1553 for (i = 0; file_name[i] != '\0'; i++)
1554 if (file_name[i] == '-') file_name[i] = '_';
1555 /* append the suffix */
1556 file_name = mputprintf(file_name, "%s", suffix);
1557 /* add the directory name if necessary */
1558 if (add_directory) {
1559 char *path_name = compose_path_name(module->dir_name, file_name);
1560 Free(file_name);
1561 file_name = path_name;
1562 }
1563 fprintf(fp, " %s", file_name);
1564 Free(file_name);
1565 }
1566
1567 /** Prints the name of the user C/C++ header file of user module \a user if the
1568 * above file exists. */
1569 static void print_header_name(FILE *fp, const struct user_struct *user)
1570 {
1571 if (user->header_name != NULL) {
1572 char *path_name = compose_path_name(user->dir_name, user->header_name);
1573 fprintf(fp, " %s", path_name);
1574 Free(path_name);
1575 }
1576 }
1577
1578 /** Prints the name of the user C/C++ source file of user module \a user if the
1579 * above file exists. */
1580 static void print_source_name(FILE *fp, const struct user_struct *user)
1581 {
1582 if (user->source_name != NULL) {
1583 char *path_name = compose_path_name(user->dir_name, user->source_name);
1584 fprintf(fp, " %s", path_name);
1585 Free(path_name);
1586 }
1587 }
1588
1589 /** Prints the name of the user C/C++ object file of user module \a user if the
1590 * above file exists (i.e. the respective source file is present). */
1591 static void print_object_name(FILE *fp, const struct user_struct *user)
1592 {
1593 if (user->source_name != NULL) {
1594 char *file_name = mprintf("%s.o", user->file_prefix);
1595 char *path_name = compose_path_name(user->dir_name, file_name);
1596 Free(file_name);
1597 fprintf(fp, " %s", path_name);
1598 Free(path_name);
1599 }
1600 }
1601
1602 static void print_shared_object_name(FILE *fp, const struct user_struct *user)
1603 {
1604 if (user->source_name != NULL) {
1605 char *file_name = mprintf("%s.so", user->file_prefix);
1606 char *path_name = compose_path_name(user->dir_name, file_name);
1607 Free(file_name);
1608 fprintf(fp, " %s", path_name);
1609 Free(path_name);
1610 }
1611 }
1612 /** Prints the splitted files' names for a given module. */
1613 static void print_splitted_file_names(FILE *fp,
1614 const struct makefile_struct *makefile, const struct module_struct *module)
1615 {
1616 if (strcmp(makefile->code_splitting_mode, "-U type") == 0) {
1617 print_generated_file_name(fp, module, FALSE, "_seq.cc");
1618 print_generated_file_name(fp, module, FALSE, "_set.cc");
1619 print_generated_file_name(fp, module, FALSE, "_seqof.cc");
1620 print_generated_file_name(fp, module, FALSE, "_setof.cc");
1621 print_generated_file_name(fp, module, FALSE, "_union.cc");
1622 }
1623 }
1624
1625 static void fprint_extra_targets(FILE* fp, struct string2_list* target_placement_list, const char* placement)
1626 {
1627 struct string2_list* act_elem = target_placement_list;
1628 while (act_elem) {
1629 if (act_elem->str1 && act_elem->str2 && (strcmp(act_elem->str2,placement)==0)) {
1630 fprintf(fp, " %s", act_elem->str1);
1631 }
1632 act_elem = act_elem->next;
1633 }
1634 }
1635
1636 #undef COMMENT_PREFIX
1637 #define COMMENT_PREFIX "# "
1638
1639 /** Prints the Makefile based on structure \a makefile. */
1640 static void print_makefile(struct makefile_struct *makefile)
1641 {
1642 boolean add_refd_prjs = makefile->sub_project_dirs && makefile->sub_project_dirs->str;
1643
1644 NOTIFY("Generating Makefile skeleton...");
1645
1646 if (makefile->force_overwrite ||
1647 get_path_status(makefile->output_file) == PS_NONEXISTENT) {
1648 size_t i;
1649 char *user_info;
1650 const char* cxx;
1651 const char* cpp;
1652 const char *rm_command = makefile->gnu_make ? "$(RM)" : "rm -f";
1653 FILE *fp;
1654 boolean run_compiler = (makefile->nASN1Modules > 0)
1655 || (makefile->nTTCN3Modules) || (makefile->nTTCN3PPModules > 0);
1656
1657 expstring_t titan_dir = 0;
1658 const char * last_slash = strrchr(program_name, '/');
1659 if (last_slash != NULL) {
1660 size_t path_len = last_slash - program_name;
1661 titan_dir = mcopystr(program_name);
1662 /* Chop off the program name, and the /bin before it (if any) */
1663 if (path_len >= 4
1664 && memcmp(titan_dir + path_len - 4, "/bin", 4) == 0) {
1665 titan_dir = mtruncstr(titan_dir, path_len - 4);
1666 }
1667 else {
1668 titan_dir = mtruncstr(titan_dir, path_len);
1669 }
1670 }
1671
1672
1673 fp = fopen(makefile->output_file, "w");
1674 if (fp == NULL){
1675 ERROR("Cannot open output file `%s' for writing: %s",
1676 makefile->output_file, strerror(errno));
1677 return;
1678 }
1679 user_info = get_user_info();
1680 fprintf(fp, "# This Makefile was generated by the Makefile Generator\n"
1681 "# of the TTCN-3 Test Executor version " PRODUCT_NUMBER "\n"
1682 "# for %s\n"
1683 COPYRIGHT_STRING "\n\n"
1684 "# The following make commands are available:\n"
1685 "# - make, make all Builds the %s.\n"
1686 "# - make archive Archives all source files.\n"
1687 "# - make check Checks the semantics of TTCN-3 and ASN.1 "
1688 "modules.\n"
1689 "# - make clean Removes all generated files.\n"
1690 "# - make compile Translates TTCN-3 and ASN.1 modules to C++.\n"
1691 "# - make dep Creates/updates dependency list.\n"
1692 "# - make executable Builds the executable test suite.\n"
1693 "# - make library Builds the library archive.\n"
1694 "# - make objects Builds the object files without linking the "
1695 "executable.\n", user_info,
1696 makefile->library ? "library archive." : "executable test suite");
1697 Free(user_info);
1698 if (makefile->dynamic)
1699 fprintf(fp, "# - make shared_objects Builds the shared object files "
1700 "without linking the executable.\n");
1701 if (makefile->preprocess)
1702 fputs("# - make preprocess Preprocess TTCN-3 files.\n", fp);
1703 if (makefile->central_storage) {
1704 fputs("# WARNING! This Makefile uses pre-compiled files from the "
1705 "following directories:\n", fp);
1706 for (i = 0; i < makefile->nBaseDirs; i++)
1707 fprintf(fp, "# %s\n", makefile->BaseDirs[i].dir_name);
1708 fputs("# The executable tests will be consistent only if all directories "
1709 "use\n"
1710 "# the same platform and the same version of TTCN-3 Test Executor "
1711 "and\n"
1712 "# C++ compiler with the same command line switches.\n\n", fp);
1713 }
1714 if (makefile->gnu_make) {
1715 fputs("# WARNING! This Makefile can be used with GNU make only.\n"
1716 "# Other versions of make may report syntax errors in it.\n\n"
1717 "#\n"
1718 "# Do NOT touch this line...\n"
1719 "#\n"
1720 ".PHONY: all shared_objects executable library objects check clean dep archive", fp);
1721 if (makefile->preprocess) fputs(" preprocess", fp);
1722 if (add_refd_prjs) {
1723 fputs("\\\n referenced-all referenced-shared_objects referenced-executable referenced-library referenced-objects referenced-check"
1724 "\\\n referenced-clean referenced-archive", fp);
1725 }
1726 fprint_extra_targets(fp, makefile->target_placement_list, "PHONY");
1727
1728 if (makefile->gcc_dep) {
1729 fputs("\n\n.SUFFIXES: .d", fp);
1730 }
1731 fputs("\n\n", fp);
1732 }
1733
1734 if (add_refd_prjs) {
1735 struct string_list* act_elem = makefile->sub_project_dirs;
1736 fputs("# This is the top level makefile of a Makefile hierarchy generated from\n"
1737 "# a Titan Project Descriptor hierarchy. List of referenced project\n"
1738 "# working directories (ordered by dependencies):\n", fp);
1739 while (act_elem) {
1740 if (act_elem->str) {
1741 fprintf(fp, "# %s\n", act_elem->str);
1742 }
1743 act_elem = act_elem->next;
1744 }
1745 fputs("REFERENCED_PROJECT_DIRS = ", fp);
1746 act_elem = makefile->sub_project_dirs;
1747 while (act_elem) {
1748 if (act_elem->str) {
1749 fprintf(fp, "%s ", act_elem->str);
1750 }
1751 act_elem = act_elem->next;
1752 }
1753 fputs("\n\n", fp);
1754 }
1755
1756 fprintf(fp, "#\n"
1757 "# Set these variables...\n"
1758 "#\n\n"
1759 "# The path of your TTCN-3 Test Executor installation:\n"
1760 "# Uncomment this line to override the environment variable.\n"
1761 "%s"
1762 "# TTCN3_DIR = %s\n"
1763 , titan_dir ?
1764 "# The value below points to the location of the TITAN version\n"
1765 "# that generated this makefile.\n" : ""
1766 , titan_dir ? titan_dir : "");
1767 if (titan_dir) Free(titan_dir);
1768
1769 if (makefile->cxxcompiler) {
1770 cxx = makefile->cxxcompiler;
1771 } else {
1772 cxx = "g++";
1773 }
1774
1775 fprintf(fp, "\n# Your platform: (SOLARIS, SOLARIS8, LINUX, FREEBSD or "
1776 "WIN32)\n"
1777 "PLATFORM = %s\n\n"
1778 "# Your C++ compiler:\n"
1779 "# (if you change the platform, you may need to change the compiler)\n"
1780 "CXX = %s \n\n", get_platform_string(), cxx);
1781
1782
1783 if (makefile->preprocess || makefile->ttcn3preprocessor) {
1784 if (makefile->ttcn3preprocessor) {
1785 cpp = makefile->ttcn3preprocessor;
1786 } else {
1787 cpp = "cpp";
1788 }
1789 fprintf(fp,"# C preprocessor used for TTCN-3 files:\n"
1790 "CPP = %s\n\n", cpp);
1791 }
1792
1793 fputs("# Flags for the C++ preprocessor (and makedepend as well):\n"
1794 "CPPFLAGS = -D$(PLATFORM) -I$(TTCN3_DIR)/include", fp);
1795
1796 if (makefile->use_runtime_2) fputs(" -DTITAN_RUNTIME_2", fp);
1797
1798 for (i = 0; i < makefile->nBaseDirs; i++) {
1799 fprintf(fp, " -I%s", makefile->BaseDirs[i].dir_name);
1800 }
1801
1802 if (makefile->prep_includes) {
1803 struct string_list* act_elem = makefile->prep_includes;
1804 while (act_elem) {
1805 if (act_elem->str) {
1806 fprintf(fp, " -I%s", act_elem->str);
1807 }
1808 act_elem = act_elem->next;
1809 }
1810 }
1811
1812 if (makefile->prep_defines) {
1813 struct string_list* act_elem = makefile->prep_defines;
1814 while (act_elem) {
1815 if (act_elem->str) {
1816 fprintf(fp, " -D%s", act_elem->str);
1817 }
1818 act_elem = act_elem->next;
1819 }
1820 }
1821
1822 fputs("\n\n", fp);
1823
1824 if (makefile->gcc_dep) {
1825 fprintf(fp, "# Flags for dependency generation\n"
1826 "CXXDEPFLAGS = -%s\n\n", strstr(cxx, "g++") ? "MM" : "xM1");
1827 }
1828
1829 if (makefile->preprocess || makefile->ttcn3_prep_includes || makefile->ttcn3_prep_defines) {
1830 fputs("# Flags for preprocessing TTCN-3 files:\n"
1831 "CPPFLAGS_TTCN3 =", fp);
1832
1833 if (makefile->preprocess) {
1834 for (i = 0; i < makefile->nBaseDirs; i++) {
1835 fprintf(fp, " -I%s", makefile->BaseDirs[i].dir_name);
1836 }
1837 }
1838 if (makefile->ttcn3_prep_includes) {
1839 struct string_list* act_elem = makefile->ttcn3_prep_includes;
1840 while (act_elem) {
1841 if (act_elem->str) {
1842 fprintf(fp, " -I%s", act_elem->str);
1843 }
1844 act_elem = act_elem->next;
1845 }
1846 }
1847 if (makefile->ttcn3_prep_defines) {
1848 struct string_list* act_elem = makefile->ttcn3_prep_defines;
1849 while (act_elem) {
1850 if (act_elem->str) {
1851 fprintf(fp, " -D%s", act_elem->str);
1852 }
1853 act_elem = act_elem->next;
1854 }
1855 }
1856 fputs("\n\n", fp);
1857 }
1858
1859 /* code splitting: command line argument wins */
1860 if (makefile->code_splitting_mode == NULL) {
1861 if (makefile->codesplittpd) {
1862 makefile->code_splitting_mode = mcopystr("-U type");
1863 }
1864 }
1865
1866 fprintf(fp, "# Flags for the C++ compiler:\n"
1867 "CXXFLAGS = %s%s %s %s\n\n"
1868 "# Flags for the linker:\n"
1869 "LDFLAGS = %s%s\n\n"
1870 "ifeq ($(PLATFORM), WIN32)\n"
1871 "# Silence linker warnings.\n"
1872 "LDFLAGS += -Wl,--enable-auto-import,--enable-runtime-pseudo-reloc\n"
1873 "endif\n\n"
1874 "# Utility to create library files\n"
1875 "AR = ar\n"
1876 "ARFLAGS = \n\n"
1877 "# Flags for the TTCN-3 and ASN.1 compiler:\n"
1878 "COMPILER_FLAGS =%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s %s\n\n"
1879 "# Execution mode: (either ttcn3 or ttcn3-parallel)\n"
1880 "TTCN3_LIB = ttcn3%s%s%s\n\n"
1881 #ifdef LICENSE
1882 "# The path of your OpenSSL installation:\n"
1883 "# If you do not have your own one, leave it unchanged.\n"
1884 "OPENSSL_DIR = $(TTCN3_DIR)\n\n"
1885 #endif
1886 "# The path of your libxml2 installation:\n"
1887 "# If you do not have your own one, leave it unchanged.\n"
1888 "XMLDIR = $(TTCN3_DIR)\n\n"
1889 "# Directory to store the archived source files:\n",
1890 makefile->dynamic ? "-Wall -fPIC" : "-Wall", /* CXXFLAGS */
1891 makefile->coverage ? " -fprofile-arcs -ftest-coverage -g" : "", /* CXXFLAGS COVERAGE */
1892 makefile->optlevel ? makefile->optlevel : "", /* CXXFLAGS optimization level */
1893 makefile->optflags ? makefile->optflags : "", /* CXXFLAGS optimization level */
1894 makefile->dynamic ? "-fPIC" : "", /* LDFLAGS */
1895 makefile->coverage ? " -fprofile-arcs -ftest-coverage -g -lgcov" : "", /* LDFLAGS COVERAGE */
1896 /* COMPILER_FLAGS */
1897 makefile->use_runtime_2 ? " -L -R " : " -L ",
1898 (makefile->code_splitting_mode ? makefile->code_splitting_mode : ""),
1899 (makefile->quietly ? " -q" : ""),
1900 (makefile->disablesubtypecheck ? " -y" : ""),
1901 (makefile->disableber ? " -b" : ""),
1902 (makefile->disableraw ? " -r" : ""),
1903 (makefile->disabletext ? " -x" : ""),
1904 (makefile->disablexer ? " -X" : ""),
1905 (makefile->disablejson ? " -j" : ""),
1906 (makefile->forcexerinasn ? " -a" : ""),
1907 (makefile->defaultasomit ? " -d" : ""),
1908 (makefile->gccmsgformat ? " -g" : ""),
1909 (makefile->linenumbersonlymsg ? " -i" : ""),
1910 (makefile->includesourceinfo ? " -l" : ""),
1911 /*(makefile->addsourcelineinfo ? " -L" : ""),*/
1912 (makefile->suppresswarnings ? " -w" : ""),
1913 (makefile->outparamboundness ? " -Y" : ""),
1914 (makefile->tcov_file_name ? makefile->tcov_file_name : ""),
1915 /* end of COMPILER FLAGS */
1916 (makefile->use_runtime_2 ? "-rt2" : ""), /* TTCN3_LIB */
1917 (makefile->single_mode ? "" : "-parallel"),
1918 (makefile->dynamic ? "-dynamic": "")
1919 );
1920 if (!makefile->gnu_make) {
1921 fputs("# Note: you can set any directory except ./archive\n", fp);
1922 }
1923 fputs("ARCHIVE_DIR = backup\n\n"
1924 "#\n"
1925 "# You may change these variables. Add your files if necessary...\n"
1926 "#\n\n"
1927 "# TTCN-3 modules of this project:\n"
1928 "TTCN3_MODULES =", fp);
1929 for (i = 0; i < makefile->nTTCN3Modules; i++) {
1930 const struct module_struct *module = makefile->TTCN3Modules + i;
1931 if (module->dir_name == NULL || !makefile->central_storage)
1932 /* If the file is in the current directory or
1933 * is not in the current directory but central directory is not used,
1934 * it goes into TTCN3_MODULES */
1935 print_file_name(fp, module);
1936 }
1937 fprint_extra_targets(fp, makefile->target_placement_list, "TTCN3_MODULES");
1938 if (makefile->preprocess) {
1939 fputs("\n\n"
1940 "# TTCN-3 modules to preprocess:\n"
1941 "TTCN3_PP_MODULES =", fp);
1942 for (i = 0; i < makefile->nTTCN3PPModules; i++) {
1943 const struct module_struct *module = makefile->TTCN3PPModules + i;
1944 if (module->dir_name == NULL || !makefile->central_storage)
1945 print_file_name(fp, module);
1946 }
1947 fprint_extra_targets(fp, makefile->target_placement_list, "TTCN3_PP_MODULES");
1948 }
1949 if (makefile->central_storage) {
1950 fputs("\n\n"
1951 "# TTCN-3 modules used from central project(s):\n"
1952 "BASE_TTCN3_MODULES =", fp);
1953 for (i = 0; i < makefile->nTTCN3Modules; i++) {
1954 const struct module_struct *module = makefile->TTCN3Modules + i;
1955 /* Central storage used AND file is not in the current directory =>
1956 * it goes into BASE_TTCN3_MODULES */
1957 if (module->dir_name != NULL) print_file_name(fp, module);
1958 }
1959 if (makefile->preprocess) {
1960 fputs("\n\n"
1961 "# TTCN-3 modules to preprocess used from central project(s):\n"
1962 "BASE_TTCN3_PP_MODULES =", fp);
1963 for (i = 0; i < makefile->nTTCN3PPModules; i++) {
1964 const struct module_struct *module = makefile->TTCN3PPModules + i;
1965 if (module->dir_name != NULL) print_file_name(fp, module);
1966 }
1967 }
1968 }
1969 if (makefile->preprocess) {
1970 fputs("\n\n"
1971 "# Files to include in TTCN-3 preprocessed modules:\n"
1972 "TTCN3_INCLUDES =", fp);
1973 for (i = 0; i < makefile->nTTCN3IncludeFiles; i++)
1974 fprintf(fp, " %s", makefile->TTCN3IncludeFiles[i]);
1975 fprint_extra_targets(fp, makefile->target_placement_list, "TTCN3_INCLUDES");
1976 }
1977 fputs("\n\n"
1978 "# ASN.1 modules of this project:\n"
1979 "ASN1_MODULES =", fp);
1980 for (i = 0; i < makefile->nASN1Modules; i++) {
1981 const struct module_struct *module = makefile->ASN1Modules + i;
1982 if (module->dir_name == NULL || !makefile->central_storage)
1983 print_file_name(fp, module);
1984 }
1985 fprint_extra_targets(fp, makefile->target_placement_list, "ASN1_MODULES");
1986 if (makefile->central_storage) {
1987 fputs("\n\n"
1988 "# ASN.1 modules used from central project(s):\n"
1989 "BASE_ASN1_MODULES =", fp);
1990 for (i = 0; i < makefile->nASN1Modules; i++) {
1991 const struct module_struct *module = makefile->ASN1Modules + i;
1992 if (module->dir_name != NULL) print_file_name(fp, module);
1993 }
1994 }
1995 if (makefile->preprocess) {
1996 fputs("\n\n"
1997 "# TTCN-3 source files generated by the C preprocessor:\n"
1998 "PREPROCESSED_TTCN3_MODULES =", fp);
1999 for (i = 0; i < makefile->nTTCN3PPModules; i++) {
2000 const struct module_struct *module = makefile->TTCN3PPModules + i;
2001 if (module->dir_name == NULL || !makefile->central_storage)
2002 print_preprocessed_file_name(fp, module);
2003 }
2004 if (makefile->central_storage) {
2005 fputs("\n\n"
2006 "# TTCN-3 files generated by the CPP used from central project(s):\n"
2007 "BASE_PREPROCESSED_TTCN3_MODULES =", fp);
2008 for (i = 0; i < makefile->nTTCN3PPModules; i++) {
2009 const struct module_struct *module = makefile->TTCN3PPModules + i;
2010 if (module->dir_name != NULL)
2011 print_preprocessed_file_name(fp, module);
2012 }
2013 }
2014 }
2015 fputs("\n\n"
2016 "# C++ source & header files generated from the TTCN-3 & ASN.1 "
2017 "modules of\n"
2018 "# this project:\n"
2019 "GENERATED_SOURCES =", fp);
2020 if (makefile->gnu_make && makefile->TTCN3ModulesRegular) {
2021 fputs(" $(TTCN3_MODULES:.ttcn=.cc)", fp);
2022 if (makefile->code_splitting_mode) {
2023 for (i = 0; i < makefile->nTTCN3Modules; i++) {
2024 const struct module_struct *module = makefile->TTCN3Modules + i;
2025 if (module->dir_name == NULL || !makefile->central_storage)
2026 print_splitted_file_names(fp, makefile, module);
2027 }
2028 }
2029 if (makefile->preprocess) {
2030 fputs(" $(TTCN3_PP_MODULES:.ttcnpp=.cc)", fp);
2031 if (makefile->code_splitting_mode) {
2032 for (i = 0; i < makefile->nTTCN3PPModules; i++) {
2033 const struct module_struct *module = makefile->TTCN3PPModules + i;
2034 if (module->dir_name == NULL || !makefile->central_storage)
2035 print_splitted_file_names(fp, makefile, module);
2036 }
2037 }
2038 }
2039 } else {
2040 for (i = 0; i < makefile->nTTCN3Modules; i++) {
2041 const struct module_struct *module = makefile->TTCN3Modules + i;
2042 if (module->dir_name == NULL || !makefile->central_storage) {
2043 print_generated_file_name(fp, module, FALSE, ".cc");
2044 if (makefile->code_splitting_mode)
2045 print_splitted_file_names(fp, makefile, module);
2046 }
2047 }
2048 if (makefile->preprocess) {
2049 for (i = 0; i < makefile->nTTCN3PPModules; i++) {
2050 const struct module_struct *module = makefile->TTCN3PPModules + i;
2051 if (module->dir_name == NULL || !makefile->central_storage) {
2052 print_generated_file_name(fp, module, FALSE, ".cc");
2053 if (makefile->code_splitting_mode)
2054 print_splitted_file_names(fp, makefile, module);
2055 }
2056 }
2057 }
2058 }
2059 if (makefile->gnu_make && makefile->ASN1ModulesRegular) {
2060 fputs(" $(ASN1_MODULES:.asn=.cc)", fp);
2061 if (makefile->code_splitting_mode) {
2062 for (i = 0; i < makefile->nASN1Modules; i++) {
2063 const struct module_struct *module = makefile->ASN1Modules + i;
2064 if (module->dir_name == NULL || !makefile->central_storage) {
2065 print_splitted_file_names(fp, makefile, module);
2066 }
2067 }
2068 }
2069 } else {
2070 for (i = 0; i < makefile->nASN1Modules; i++) {
2071 const struct module_struct *module = makefile->ASN1Modules + i;
2072 if (module->dir_name == NULL || !makefile->central_storage) {
2073 print_generated_file_name(fp, module, FALSE, ".cc");
2074 if (makefile->code_splitting_mode)
2075 print_splitted_file_names(fp, makefile, module);
2076 }
2077 }
2078 }
2079
2080 fputs("\nGENERATED_HEADERS =", fp);
2081 if (makefile->gnu_make) {
2082 fputs(" $(GENERATED_SOURCES:.cc=.hh)", fp);
2083 } else {
2084 for (i = 0; i < makefile->nTTCN3Modules; i++) {
2085 const struct module_struct *module = makefile->TTCN3Modules + i;
2086 if (module->dir_name == NULL || !makefile->central_storage)
2087 print_generated_file_name(fp, module, FALSE, ".hh");
2088 }
2089 if (makefile->preprocess) {
2090 for (i = 0; i < makefile->nTTCN3PPModules; i++) {
2091 const struct module_struct *module = makefile->TTCN3PPModules + i;
2092 if (module->dir_name == NULL || !makefile->central_storage)
2093 print_generated_file_name(fp, module, FALSE, ".hh");
2094 }
2095 }
2096 for (i = 0; i < makefile->nASN1Modules; i++) {
2097 const struct module_struct *module = makefile->ASN1Modules + i;
2098 if (module->dir_name == NULL || !makefile->central_storage)
2099 print_generated_file_name(fp, module, FALSE, ".hh");
2100 }
2101 }
2102 if (makefile->central_storage) {
2103 fputs("\n\n"
2104 "# C++ source & header files generated from the TTCN-3 & ASN.1 "
2105 "modules of\n"
2106 "# central project(s):\n"
2107 "BASE_GENERATED_SOURCES =", fp);
2108 if (makefile->gnu_make && makefile->BaseTTCN3ModulesRegular) {
2109 fputs(" $(BASE_TTCN3_MODULES:.ttcn=.cc)", fp);
2110 if (makefile->code_splitting_mode) {
2111 for (i = 0; i < makefile->nTTCN3Modules; i++) {
2112 const struct module_struct *module = makefile->TTCN3Modules + i;
2113 if (module->dir_name != NULL) {
2114 print_splitted_file_names(fp, makefile, module);
2115 }
2116 }
2117 }
2118 if (makefile->preprocess) {
2119 fputs(" $(BASE_TTCN3_PP_MODULES:.ttcnpp=.cc)", fp);
2120 if (makefile->code_splitting_mode) {
2121 for (i = 0; i < makefile->nTTCN3PPModules; i++) {
2122 const struct module_struct *module = makefile->TTCN3PPModules + i;
2123 if (module->dir_name != NULL) {
2124 print_splitted_file_names(fp, makefile, module);
2125 }
2126 }
2127 }
2128 }
2129 } else {
2130 for (i = 0; i < makefile->nTTCN3Modules; i++) {
2131 const struct module_struct *module = makefile->TTCN3Modules + i;
2132 if (module->dir_name != NULL) {
2133 print_generated_file_name(fp, module, TRUE, ".cc");
2134 if (makefile->code_splitting_mode)
2135 print_splitted_file_names(fp, makefile, module);
2136 }
2137 }
2138 if (makefile->preprocess) {
2139 for (i = 0; i < makefile->nTTCN3PPModules; i++) {
2140 const struct module_struct *module = makefile->TTCN3PPModules + i;
2141 if (module->dir_name != NULL) {
2142 print_generated_file_name(fp, module, TRUE, ".cc");
2143 if (makefile->code_splitting_mode)
2144 print_splitted_file_names(fp, makefile, module);
2145 }
2146 }
2147 }
2148 }
2149 if (makefile->gnu_make && makefile->BaseASN1ModulesRegular) {
2150 fputs(" $(BASE_ASN1_MODULES:.asn=.cc)", fp);
2151 if (makefile->code_splitting_mode) {
2152 for (i = 0; i < makefile->nASN1Modules; i++) {
2153 const struct module_struct *module = makefile->ASN1Modules + i;
2154 if (module->dir_name != NULL) {
2155 print_splitted_file_names(fp, makefile, module);
2156 }
2157 }
2158 }
2159 } else {
2160 for (i = 0; i < makefile->nASN1Modules; i++) {
2161 const struct module_struct *module = makefile->ASN1Modules + i;
2162 if (module->dir_name != NULL) {
2163 print_generated_file_name(fp, module, TRUE, ".cc");
2164 if (makefile->code_splitting_mode)
2165 print_splitted_file_names(fp, makefile, module);
2166 }
2167 }
2168 }
2169 fputs("\nBASE_GENERATED_HEADERS =", fp);
2170 if (makefile->gnu_make) {
2171 fputs(" $(BASE_GENERATED_SOURCES:.cc=.hh)", fp);
2172 } else {
2173 for (i = 0; i < makefile->nTTCN3Modules; i++) {
2174 const struct module_struct *module = makefile->TTCN3Modules + i;
2175 if (module->dir_name != NULL)
2176 print_generated_file_name(fp, module, TRUE, ".hh");
2177 }
2178 if (makefile->preprocess) {
2179 for (i = 0; i < makefile->nTTCN3PPModules; i++) {
2180 const struct module_struct *module = makefile->TTCN3PPModules + i;
2181 if (module->dir_name != NULL)
2182 print_generated_file_name(fp, module, TRUE, ".hh");
2183 }
2184 }
2185 for (i = 0; i < makefile->nASN1Modules; i++) {
2186 const struct module_struct *module = makefile->ASN1Modules + i;
2187 if (module->dir_name != NULL)
2188 print_generated_file_name(fp, module, TRUE, ".hh");
2189 }
2190 }
2191 }
2192 fputs("\n\n"
2193 "# C/C++ Source & header files of Test Ports, external functions "
2194 "and\n"
2195 "# other modules:\n"
2196 "USER_SOURCES =", fp);
2197 for (i = 0; i < makefile->nUserFiles; i++) {
2198 const struct user_struct *user = makefile->UserFiles + i;
2199 if (user->dir_name == NULL || !makefile->central_storage)
2200 print_source_name(fp, user);
2201 }
2202 fprint_extra_targets(fp, makefile->target_placement_list, "USER_SOURCES");
2203 fputs("\nUSER_HEADERS =", fp);
2204 if (makefile->gnu_make && makefile->UserHeadersRegular) {
2205 fputs(" $(USER_SOURCES:.cc=.hh)", fp);
2206 } else {
2207 for (i = 0; i < makefile->nUserFiles; i++) {
2208 const struct user_struct *user = makefile->UserFiles + i;
2209 if (user->dir_name == NULL || !makefile->central_storage)
2210 print_header_name(fp, user);
2211 }
2212 }
2213 fprint_extra_targets(fp, makefile->target_placement_list, "USER_HEADERS");
2214 if (makefile->central_storage) {
2215 fputs("\n\n"
2216 "# C/C++ Source & header files of Test Ports, external functions "
2217 "and\n"
2218 "# other modules used from central project(s):\n"
2219 "BASE_USER_SOURCES =", fp);
2220 for (i = 0; i < makefile->nUserFiles; i++) {
2221 const struct user_struct *user = makefile->UserFiles + i;
2222 if (user->dir_name != NULL)
2223 print_source_name(fp, user);
2224 }
2225 fputs("\nBASE_USER_HEADERS =", fp);
2226 if (makefile->gnu_make && makefile->BaseUserHeadersRegular) {
2227 fputs(" $(BASE_USER_SOURCES:.cc=.hh)", fp);
2228 } else {
2229 for (i = 0; i < makefile->nUserFiles; i++) {
2230 const struct user_struct *user = makefile->UserFiles + i;
2231 if (user->dir_name != NULL)
2232 print_header_name(fp, user);
2233 }
2234 }
2235 }
2236
2237 if (makefile->dynamic) {
2238 fputs("\n\n"
2239 "# Shared object files of this project:\n"
2240 "SHARED_OBJECTS =", fp);
2241 if (makefile->gnu_make) {
2242 fputs(" $(GENERATED_SOURCES:.cc=.so)", fp);
2243 } else {
2244 for (i = 0; i < makefile->nTTCN3Modules; i++) {
2245 const struct module_struct *module = makefile->TTCN3Modules + i;
2246 if (module->dir_name == NULL || !makefile->central_storage) {
2247 print_generated_file_name(fp, module, FALSE, ".so");
2248 if (makefile->code_splitting_mode != NULL)
2249 if (strcmp(makefile->code_splitting_mode, "-U type") == 0) {
2250 print_generated_file_name(fp, module, FALSE, "_seq.so");
2251 print_generated_file_name(fp, module, FALSE, "_set.so");
2252 print_generated_file_name(fp, module, FALSE, "_seqof.so");
2253 print_generated_file_name(fp, module, FALSE, "_setof.so");
2254 print_generated_file_name(fp, module, FALSE, "_union.so");
2255 }
2256 }
2257 }
2258 if (makefile->preprocess) {
2259 for (i = 0; i < makefile->nTTCN3PPModules; i++) {
2260 const struct module_struct *module = makefile->TTCN3PPModules + i;
2261 if (module->dir_name == NULL || !makefile->central_storage) {
2262 print_generated_file_name(fp, module, FALSE, ".so");
2263 if (makefile->code_splitting_mode != NULL)
2264 if (strcmp(makefile->code_splitting_mode, "-U type") == 0) {
2265 print_generated_file_name(fp, module, FALSE, "_seq.so");
2266 print_generated_file_name(fp, module, FALSE, "_set.so");
2267 print_generated_file_name(fp, module, FALSE, "_seqof.so");
2268 print_generated_file_name(fp, module, FALSE, "_setof.so");
2269 print_generated_file_name(fp, module, FALSE, "_union.so");
2270 }
2271 }
2272 }
2273 }
2274 for (i = 0; i < makefile->nASN1Modules; i++) {
2275 const struct module_struct *module = makefile->ASN1Modules + i;
2276 if (module->dir_name == NULL || !makefile->central_storage) {
2277 print_generated_file_name(fp, module, FALSE, ".so");
2278 if (makefile->code_splitting_mode != NULL)
2279 if (strcmp(makefile->code_splitting_mode, "-U type") == 0) {
2280 print_generated_file_name(fp, module, FALSE, "_seq.so");
2281 print_generated_file_name(fp, module, FALSE, "_set.so");
2282 print_generated_file_name(fp, module, FALSE, "_seqof.so");
2283 print_generated_file_name(fp, module, FALSE, "_setof.so");
2284 print_generated_file_name(fp, module, FALSE, "_union.so");
2285 }
2286 }
2287 }
2288 }
2289 if (makefile->gnu_make && makefile->UserSourcesRegular) {
2290 fputs(" $(USER_SOURCES:.cc=.so)", fp);
2291 } else {
2292 for (i = 0; i < makefile->nUserFiles; i++) {
2293 const struct user_struct *user = makefile->UserFiles + i;
2294 if (user->dir_name == NULL || !makefile->central_storage)
2295 print_shared_object_name(fp, user);
2296 }
2297 }
2298 }
2299
2300 fputs("\n\n"
2301 "# Object files of this project that are needed for the executable "
2302 "test suite:\n"
2303 "OBJECTS = $(GENERATED_OBJECTS) $(USER_OBJECTS)\n\n" /* never := */
2304 "GENERATED_OBJECTS =", fp);
2305 if (makefile->gnu_make) {
2306 fputs(" $(GENERATED_SOURCES:.cc=.o)", fp);
2307 } else {
2308 for (i = 0; i < makefile->nTTCN3Modules; i++) {
2309 const struct module_struct *module = makefile->TTCN3Modules + i;
2310 if (module->dir_name == NULL || !makefile->central_storage) {
2311 print_generated_file_name(fp, module, FALSE, ".o");
2312 if (makefile->code_splitting_mode != NULL)
2313 if (strcmp(makefile->code_splitting_mode, "-U type") == 0) {
2314 print_generated_file_name(fp, module, FALSE, "_seq.o");
2315 print_generated_file_name(fp, module, FALSE, "_set.o");
2316 print_generated_file_name(fp, module, FALSE, "_seqof.o");
2317 print_generated_file_name(fp, module, FALSE, "_setof.o");
2318 print_generated_file_name(fp, module, FALSE, "_union.o");
2319 }
2320 }
2321 }
2322 if (makefile->preprocess) {
2323 for (i = 0; i < makefile->nTTCN3PPModules; i++) {
2324 const struct module_struct *module = makefile->TTCN3PPModules + i;
2325 if (module->dir_name == NULL || !makefile->central_storage) {
2326 print_generated_file_name(fp, module, FALSE, ".o");
2327 if (makefile->code_splitting_mode != NULL)
2328 if (strcmp(makefile->code_splitting_mode, "-U type") == 0) {
2329 print_generated_file_name(fp, module, FALSE, "_seq.o");
2330 print_generated_file_name(fp, module, FALSE, "_set.o");
2331 print_generated_file_name(fp, module, FALSE, "_seqof.o");
2332 print_generated_file_name(fp, module, FALSE, "_setof.o");
2333 print_generated_file_name(fp, module, FALSE, "_union.o");
2334 }
2335 }
2336 }
2337 }
2338 for (i = 0; i < makefile->nASN1Modules; i++) {
2339 const struct module_struct *module = makefile->ASN1Modules + i;
2340 if (module->dir_name == NULL || !makefile->central_storage) {
2341 print_generated_file_name(fp, module, FALSE, ".o");
2342 if (makefile->code_splitting_mode != NULL)
2343 if (strcmp(makefile->code_splitting_mode, "-U type") == 0) {
2344 print_generated_file_name(fp, module, FALSE, "_seq.o");
2345 print_generated_file_name(fp, module, FALSE, "_set.o");
2346 print_generated_file_name(fp, module, FALSE, "_seqof.o");
2347 print_generated_file_name(fp, module, FALSE, "_setof.o");
2348 print_generated_file_name(fp, module, FALSE, "_union.o");
2349 }
2350 }
2351 }
2352 }
2353
2354 fputs("\n\nUSER_OBJECTS =", fp);
2355 if (makefile->gnu_make && makefile->UserSourcesRegular) {
2356 fputs(" $(USER_SOURCES:.cc=.o)", fp);
2357 } else {
2358 for (i = 0; i < makefile->nUserFiles; i++) {
2359 const struct user_struct *user = makefile->UserFiles + i;
2360 if (user->dir_name == NULL || !makefile->central_storage)
2361 print_object_name(fp, user);
2362 }
2363 }
2364 fprint_extra_targets(fp, makefile->target_placement_list, "USER_OBJECTS");
2365
2366 if (makefile->gcc_dep) {
2367 /* GNU Make processes included makefiles in reverse order. By putting
2368 * user sources first, their .d will be generated last, after the
2369 * GENERATED_SOURCES (and GENERATED_HEADERS) have been created.
2370 * This avoid spurious errors during incremental dependency generation */
2371 fputs("\n\nDEPFILES = $(USER_OBJECTS:.o=.d) $(GENERATED_OBJECTS:.o=.d)", fp);
2372 }
2373
2374 if (makefile->central_storage) {
2375 if (makefile->dynamic) {
2376 fputs("\n\n"
2377 "# Shared object files of central project(s):\n"
2378 "BASE_SHARED_OBJECTS =", fp);
2379 if (makefile->gnu_make) {
2380 fputs(" $(BASE_GENERATED_SOURCES:.cc=.so)", fp);
2381 } else {
2382 for (i = 0; i < makefile->nTTCN3Modules; i++) {
2383 const struct module_struct *module = makefile->TTCN3Modules + i;
2384 if (module->dir_name != NULL)
2385 print_generated_file_name(fp, module, TRUE, ".so");
2386 }
2387 if (makefile->preprocess) {
2388 for (i = 0; i < makefile->nTTCN3PPModules; i++) {
2389 const struct module_struct *module =
2390 makefile->TTCN3PPModules + i;
2391 if (module->dir_name != NULL)
2392 print_generated_file_name(fp, module, TRUE, ".so");
2393 }
2394 }
2395 for (i = 0; i < makefile->nASN1Modules; i++) {
2396 const struct module_struct *module = makefile->ASN1Modules + i;
2397 if (module->dir_name != NULL)
2398 print_generated_file_name(fp, module, TRUE, ".so");
2399 }
2400 }
2401 if (makefile->gnu_make && makefile->BaseUserSourcesRegular) {
2402 fputs(" $(BASE_USER_SOURCES:.cc=.so)", fp);
2403 } else {
2404 for (i = 0; i < makefile->nUserFiles; i++) {
2405 const struct user_struct *user = makefile->UserFiles + i;
2406 if (user->dir_name != NULL)
2407 print_shared_object_name(fp, user);
2408 }
2409 }
2410 } /* if dynamic */
2411 fputs("\n\n"
2412 "# Object files of central project(s) that are needed for the "
2413 "executable test suite:\n"
2414 "BASE_OBJECTS =", fp);
2415 if (makefile->gnu_make) {
2416 fputs(" $(BASE_GENERATED_SOURCES:.cc=.o)", fp);
2417 } else {
2418 for (i = 0; i < makefile->nTTCN3Modules; i++) {
2419 const struct module_struct *module = makefile->TTCN3Modules + i;
2420 if (module->dir_name != NULL)
2421 print_generated_file_name(fp, module, TRUE, ".o");
2422 }
2423 if (makefile->preprocess) {
2424 for (i = 0; i < makefile->nTTCN3PPModules; i++) {
2425 const struct module_struct *module = makefile->TTCN3PPModules + i;
2426 if (module->dir_name != NULL)
2427 print_generated_file_name(fp, module, TRUE, ".o");
2428 }
2429 }
2430 for (i = 0; i < makefile->nASN1Modules; i++) {
2431 const struct module_struct *module = makefile->ASN1Modules + i;
2432 if (module->dir_name != NULL)
2433 print_generated_file_name(fp, module, TRUE, ".o");
2434 }
2435 }
2436 if (makefile->gnu_make && makefile->BaseUserSourcesRegular) {
2437 fputs(" $(BASE_USER_SOURCES:.cc=.o)", fp);
2438 } else {
2439 for (i = 0; i < makefile->nUserFiles; i++) {
2440 const struct user_struct *user = makefile->UserFiles + i;
2441 if (user->dir_name != NULL)
2442 print_object_name(fp, user);
2443 }
2444 }
2445 }
2446 fputs("\n\n"
2447 "# Other files of the project (Makefile, configuration files, etc.)\n"
2448 "# that will be added to the archived source files:\n"
2449 "OTHER_FILES =", fp);
2450 for (i = 0; i < makefile->nOtherFiles; i++)
2451 fprintf(fp, " %s", makefile->OtherFiles[i]);
2452 fprint_extra_targets(fp, makefile->target_placement_list, "OTHER_FILES");
2453
2454 if (makefile->ets_name) {
2455 const char *ets_suffix = NULL;
2456 /* EXECUTABLE variable */
2457 fprintf(fp, "\n\n"
2458 "# The name of the executable test suite:\n"
2459 "EXECUTABLE = %s", makefile->ets_name);
2460 #ifdef WIN32
2461 {
2462 /* add the .exe suffix unless it is already present */
2463 ets_suffix = get_suffix(makefile->ets_name);
2464 if (ets_suffix == NULL || strcmp(ets_suffix, "exe"))
2465 fputs(".exe", fp);
2466 }
2467 #endif
2468 fputs("\n", fp);
2469
2470 /* LIBRARY variable */
2471 ets_suffix = get_suffix(makefile->ets_name);
2472 if (ets_suffix != NULL && !strcmp(ets_suffix, "exe")) {
2473 char* name_prefix = cut_suffix(makefile->ets_name);
2474 fprintf(fp, "\n\nLIBRARY = %s%s\n", name_prefix ? name_prefix : "library",
2475 makefile->dynamic ? "_lib.so" : ".a");
2476 Free(name_prefix);
2477 } else {
2478 fprintf(fp, "\n\nLIBRARY = %s%s\n", makefile->ets_name,
2479 makefile->dynamic ? "_lib.so" : ".a");
2480 }
2481
2482 } else {
2483 fputs("\n\n"
2484 "# The name of the executable test suite:\n"
2485 "EXECUTABLE =\n"
2486 "LIBRARY =\n", fp);
2487 }
2488
2489 fprintf(fp, "\n"
2490 "TARGET = $(%s)", makefile->library ? "LIBRARY" : "EXECUTABLE");
2491
2492 fputs("\n\n"
2493 "#\n"
2494 "# Do not modify these unless you know what you are doing...\n"
2495 "# Platform specific additional libraries:\n"
2496 "#\n", fp);
2497
2498 fputs("SOLARIS_LIBS = -lsocket -lnsl -lxml2", fp);
2499 #ifdef USAGE_STATS
2500 fputs(" -lresolv", fp);
2501 #endif
2502 if (makefile->solspeclibraries) {
2503 struct string_list* act_elem = makefile->solspeclibraries;
2504 while (act_elem) {
2505 if (act_elem->str) {
2506 fprintf(fp, " -l%s", act_elem->str);
2507 }
2508 act_elem = act_elem->next;
2509 }
2510 }
2511 fputs("\n", fp);
2512
2513 fputs("SOLARIS8_LIBS = -lsocket -lnsl -lxml2", fp);
2514 #ifdef USAGE_STATS
2515 fputs(" -lresolv", fp);
2516 #endif
2517 if (makefile->sol8speclibraries) {
2518 struct string_list* act_elem = makefile->sol8speclibraries;
2519 while (act_elem) {
2520 if (act_elem->str) {
2521 fprintf(fp, " -l%s", act_elem->str);
2522 }
2523 act_elem = act_elem->next;
2524 }
2525 }
2526 fputs("\n", fp);
2527
2528 fputs("LINUX_LIBS = -lxml2", fp);
2529 #ifdef USAGE_STATS
2530 fputs(" -lpthread -lrt", fp);
2531 #endif
2532 if (makefile->linuxspeclibraries) {
2533 struct string_list* act_elem = makefile->linuxspeclibraries;
2534 while (act_elem) {
2535 if (act_elem->str) {
2536 fprintf(fp, " -l%s", act_elem->str);
2537 }
2538 act_elem = act_elem->next;
2539 }
2540 }
2541 fputs("\n", fp);
2542
2543 fputs("FREEBSD_LIBS = -lxml2", fp);
2544 if (makefile->freebsdspeclibraries) {
2545 struct string_list* act_elem = makefile->freebsdspeclibraries;
2546 while (act_elem) {
2547 if (act_elem->str) {
2548 fprintf(fp, " -l%s", act_elem->str);
2549 }
2550 act_elem = act_elem->next;
2551 }
2552 }
2553 fputs("\n", fp);
2554
2555 fputs("WIN32_LIBS = -lxml2", fp);
2556 if (makefile->win32speclibraries) {
2557 struct string_list* act_elem = makefile->win32speclibraries;
2558 while (act_elem) {
2559 if (act_elem->str) {
2560 fprintf(fp, " -l%s", act_elem->str);
2561 }
2562 act_elem = act_elem->next;
2563 }
2564 }
2565 fputs("\n\n", fp);
2566
2567 fputs("#\n"
2568 "# Rules for building the executable...\n"
2569 "#\n\n", fp);
2570 fprintf(fp, "all:%s $(TARGET) ;\n\n", add_refd_prjs?" referenced-all":"");
2571
2572 if (makefile->dynamic) {
2573 fprintf(fp, "shared_objects:%s $(SHARED_OBJECTS) ;\n\n", add_refd_prjs?" referenced-shared_objects":"");
2574 }
2575
2576 fprintf(fp,
2577 "executable:%s $(EXECUTABLE) ;\n\n"
2578 "library:%s $(LIBRARY) ;\n\n"
2579 "objects:%s $(OBJECTS) compile;\n\n", add_refd_prjs?" referenced-executable":"", add_refd_prjs?" referenced-library":"", add_refd_prjs?" referenced-objects":"");
2580
2581 /* target $(EXECUTABLE) */
2582 if (makefile->dynamic && makefile->library) {
2583 /* There is no need to create the .so for all the source files */
2584 fputs("$(EXECUTABLE): $(LIBRARY)\n"
2585 "\tif $(CXX) $(LDFLAGS) -o $@ $(LIBRARY)", fp);
2586 } else {
2587 fprintf(fp, "$(EXECUTABLE): %s", makefile->dynamic ? "$(SHARED_OBJECTS)" : "$(OBJECTS)");
2588 if (makefile->central_storage) {
2589 if (makefile->dynamic) {
2590 fputs(" $(BASE_SHARED_OBJECTS)", fp);
2591 } else {
2592 fputs(" $(BASE_OBJECTS)", fp);
2593 }
2594 }
2595 fputs("\n"
2596 "\tif $(CXX) $(LDFLAGS) -o $@ ", fp); /* start writing the link step */
2597 if (makefile->gnu_make) fputs("$^", fp);
2598 else {
2599 if (makefile->dynamic) {
2600 fputs("$(SHARED_OBJECTS)", fp);
2601 if (makefile->central_storage)
2602 fputs(" $(BASE_SHARED_OBJECTS)", fp);
2603 } else {
2604 fputs("$(OBJECTS)", fp);
2605 if (makefile->central_storage)
2606 fputs(" $(BASE_OBJECTS)", fp);
2607 }
2608 }
2609 }
2610
2611 if (makefile->additionalObjects) {
2612 struct string_list* act_elem = makefile->additionalObjects;
2613 while (act_elem) {
2614 if (act_elem->str) {
2615 fprintf(fp, " %s", act_elem->str);
2616 }
2617 act_elem = act_elem->next;
2618 }
2619 }
2620
2621 fprintf(fp, " \\\n"
2622 "\t-L$(TTCN3_DIR)/lib -l$(TTCN3_LIB)"
2623 " \\\n"
2624 "\t-L$(OPENSSL_DIR)/lib -lcrypto");
2625 if (makefile->linkerlibraries) {
2626 struct string_list* act_elem = makefile->linkerlibraries;
2627 while (act_elem) {
2628 if (act_elem->str) {
2629 fprintf(fp, " -l%s", act_elem->str);
2630 }
2631 act_elem = act_elem->next;
2632 }
2633 }
2634 if (makefile->linkerlibsearchpath) {
2635 struct string_list* act_elem = makefile->linkerlibsearchpath;
2636 while (act_elem) {
2637 if (act_elem->str) {
2638 fprintf(fp, " -L%s", act_elem->str);
2639 }
2640 act_elem = act_elem->next;
2641 }
2642 }
2643 fprintf(fp, " \\\n"
2644 "\t-L$(XMLDIR)/lib $($(PLATFORM)_LIBS); \\\n"
2645 "\tthen : ; else $(TTCN3_DIR)/bin/titanver $(OBJECTS); exit 1; fi\n");
2646 /* If the compiler will not be run because there are no TTCN(PP) or ASN.1
2647 * files, create the "compile" marker file which is checked by the
2648 * superior makefile if using this project as central storage */
2649 if (!run_compiler) fputs("\ttouch compile\n", fp);
2650 /* End of target $(EXECUTABLE) */
2651
2652 /* target $(LIBRARY) */
2653 if (makefile->dynamic) {
2654 fputs("\n"
2655 "$(LIBRARY): $(OBJECTS)\n"
2656 "\t$(CXX) -shared -o $@ $(OBJECTS)", fp);
2657 if (makefile->central_storage) {
2658 fputs(" $(BASE_SHARED_OBJECTS)", fp);
2659 }
2660 } else {
2661 fputs("\n"
2662 "$(LIBRARY): $(OBJECTS)\n"
2663 "\t$(AR) -r $(ARFLAGS) $(LIBRARY) $(OBJECTS)", fp);
2664 if (makefile->central_storage) {
2665 fputs(" $(BASE_OBJECTS)", fp);
2666 }
2667 }
2668
2669 fputs("\n\n.cc.o .c.o:\n"
2670 "\t$(CXX) -c $(CPPFLAGS) $(CXXFLAGS) -o $@ $<\n\n", fp);
2671
2672 if (makefile->gcc_dep) {
2673 fputs(".cc.d .c.d:\n"
2674 "\t@echo Creating dependency file for '$<'; set -e; \\\n"
2675 "\t$(CXX) $(CXXDEPFLAGS) $(CPPFLAGS) $(CXXFLAGS) $< \\\n"
2676 "\t| sed 's/\\($*\\)\\.o[ :]*/\\1.o $@ : /g' > $@; \\\n"
2677 "\t[ -s $@ ] || rm -f $@\n\n", fp);
2678 /* "set -e" causes bash to exit the script if any statement
2679 * returns nonzero (failure).
2680 * The sed line transforms the first line of the dependency from
2681 * "x.o: x.cc" to "x.o x.d: x.cc", making the dependency file depend
2682 * on the source and headers.
2683 * [ -s x.d ] checks that the generated dependency is not empty;
2684 * otherwise it gets deleted.
2685 */
2686 }
2687
2688 if (makefile->dynamic) {
2689 fputs("%.so: %.o\n"
2690 "\t$(CXX) -shared -o $@ $<\n\n", fp);
2691 }
2692
2693 if (makefile->preprocess) {
2694 fputs("%.ttcn: %.ttcnpp $(TTCN3_INCLUDES)\n"
2695 "\t$(CPP) -x c -nostdinc $(CPPFLAGS_TTCN3) $< $@\n\n"
2696 "preprocess: $(PREPROCESSED_TTCN3_MODULES) ;\n\n", fp);
2697 }
2698
2699 if (makefile->central_storage) {
2700 boolean is_first = TRUE;
2701 fputs("$(GENERATED_SOURCES) $(GENERATED_HEADERS): compile-all compile ", fp);
2702 if (add_refd_prjs) fputs("referenced-dep", fp);
2703 /* These extra compile dependencies for the generated .cc are here to
2704 * check if all the referenced projects are up to date.
2705 * If the referenced projects are built too then they are not needed
2706 * (and cause problems as the included .d depends on the .cc).
2707 */
2708 if (!add_refd_prjs) for (i = 0; i < makefile->nBaseDirs; i++) {
2709 const struct base_dir_struct *base_dir = makefile->BaseDirs + i;
2710 if (base_dir->has_modules) {
2711 if (is_first) {
2712 fputs(" \\\n", fp);
2713 is_first = FALSE;
2714 } else putc(' ', fp);
2715 fprintf(fp, "%s/compile", base_dir->dir_name);
2716 }
2717 }
2718
2719 if (makefile->preprocess) {
2720 fprintf(fp, "\n"
2721 "\t@if [ ! -f $@ ]; then %s compile-all; $(MAKE) compile-all; fi\n"
2722 "\n"
2723 "check:%s $(TTCN3_MODULES) $(BASE_TTCN3_MODULES) \\\n"
2724 "\t$(PREPROCESSED_TTCN3_MODULES) $(BASE_PREPROCESSED_TTCN3_MODULES) "
2725 "\\\n"
2726 "\t$(ASN1_MODULES) $(BASE_ASN1_MODULES)\n"
2727 "\t$(TTCN3_DIR)/bin/compiler -s $(COMPILER_FLAGS) ", rm_command, add_refd_prjs?" referenced-check":"");
2728 if (makefile->gnu_make) {
2729 if (add_refd_prjs) // referenced-check cannot be compiled it is not a ttcn modul
2730 fputs("$(TTCN3_MODULES) $(BASE_TTCN3_MODULES) \\\n"
2731 "\t$(PREPROCESSED_TTCN3_MODULES) $(BASE_PREPROCESSED_TTCN3_MODULES) "
2732 "\\\n"
2733 "\t$(ASN1_MODULES) $(BASE_ASN1_MODULES)\n", fp);
2734 else
2735 fputs("$^", fp);
2736 }
2737 else {
2738 fputs("\\\n"
2739 "\t$(TTCN3_MODULES) $(BASE_TTCN3_MODULES) \\\n"
2740 "\t$(PREPROCESSED_TTCN3_MODULES) "
2741 "$(BASE_PREPROCESSED_TTCN3_MODULES) \\\n"
2742 "\t$(ASN1_MODULES) $(BASE_ASN1_MODULES)", fp);
2743 }
2744 fputs("\n\n"
2745 "compile: $(TTCN3_MODULES) $(PREPROCESSED_TTCN3_MODULES) "
2746 "$(ASN1_MODULES)\n"
2747 "\t$(TTCN3_DIR)/bin/compiler $(COMPILER_FLAGS) \\\n"
2748 "\t$(TTCN3_MODULES) $(BASE_TTCN3_MODULES) \\\n"
2749 "\t$(PREPROCESSED_TTCN3_MODULES) "
2750 "$(BASE_PREPROCESSED_TTCN3_MODULES) \\\n"
2751 "\t$(ASN1_MODULES) $(BASE_ASN1_MODULES) - $?\n"
2752 "\ttouch $@\n"
2753 "\n"
2754 "compile-all: $(BASE_TTCN3_MODULES) "
2755 "$(BASE_PREPROCESSED_TTCN3_MODULES) \\\n"
2756 "$(BASE_ASN1_MODULES)\n"
2757 "\t$(MAKE) preprocess\n"
2758 "\t$(TTCN3_DIR)/bin/compiler $(COMPILER_FLAGS) \\\n"
2759 "\t$(TTCN3_MODULES) $(BASE_TTCN3_MODULES) \\\n"
2760 "\t$(PREPROCESSED_TTCN3_MODULES) $(BASE_PREPROCESSED_TTCN3_MODULES) "
2761 "\\\n"
2762 "\t$(ASN1_MODULES) $(BASE_ASN1_MODULES) \\\n"
2763 "\t- $(TTCN3_MODULES) $(PREPROCESSED_TTCN3_MODULES) $(ASN1_MODULES)\n"
2764 "\ttouch $@ compile\n\n", fp);
2765 } else {
2766 fprintf(fp, "\n"
2767 "\t@if [ ! -f $@ ]; then %s compile-all; $(MAKE) compile-all; fi\n"
2768 "\n"
2769 "check:%s $(TTCN3_MODULES) $(BASE_TTCN3_MODULES) \\\n"
2770 "\t$(ASN1_MODULES) $(BASE_ASN1_MODULES)\n"
2771 "\t$(TTCN3_DIR)/bin/compiler -s $(COMPILER_FLAGS) ", rm_command, add_refd_prjs?" referenced-check":"");
2772 if (makefile->gnu_make) {
2773 if (add_refd_prjs) // referenced-check cannot be compiled it is not a ttcn modul
2774 fputs("$(TTCN3_MODULES) $(BASE_TTCN3_MODULES) \\\n"
2775 "\t$(ASN1_MODULES) $(BASE_ASN1_MODULES)\n", fp);
2776 else
2777 fputs("$^", fp);
2778 }
2779 else {
2780 fputs("\\\n"
2781 "\t$(TTCN3_MODULES) $(BASE_TTCN3_MODULES) \\\n"
2782 "\t$(ASN1_MODULES) $(BASE_ASN1_MODULES)", fp);
2783 }
2784 fputs("\n\n"
2785 "compile: $(TTCN3_MODULES) $(ASN1_MODULES)\n"
2786 "\t$(TTCN3_DIR)/bin/compiler $(COMPILER_FLAGS) \\\n"
2787 "\t$(TTCN3_MODULES) $(BASE_TTCN3_MODULES) \\\n"
2788 "\t$(ASN1_MODULES) $(BASE_ASN1_MODULES) \\\n"
2789 "\t- $?\n"
2790 "\ttouch $@\n"
2791 "\n"
2792 "compile-all: $(BASE_TTCN3_MODULES) $(BASE_ASN1_MODULES)\n"
2793 "\t$(TTCN3_DIR)/bin/compiler $(COMPILER_FLAGS) \\\n"
2794 "\t$(TTCN3_MODULES) $(BASE_TTCN3_MODULES) \\\n"
2795 "\t$(ASN1_MODULES) $(BASE_ASN1_MODULES) \\\n"
2796 "\t- $(TTCN3_MODULES) $(ASN1_MODULES)\n"
2797 "\ttouch $@ compile\n\n", fp);
2798 }
2799 for (i = 0; i < makefile->nBaseDirs; i++) {
2800 const struct base_dir_struct *base_dir = makefile->BaseDirs + i;
2801 if (base_dir->has_modules) {
2802 size_t j;
2803 fprintf(fp, "%s/compile:", base_dir->dir_name);
2804 for (j = 0; j < makefile->nTTCN3Modules; j++) {
2805 const struct module_struct *module = makefile->TTCN3Modules + j;
2806 if (module->dir_name != NULL &&
2807 !strcmp(base_dir->dir_name, module->dir_name))
2808 print_file_name(fp, module);
2809 }
2810 for (j = 0; j < makefile->nTTCN3PPModules; j++) {
2811 const struct module_struct *module = makefile->TTCN3PPModules + j;
2812 if (module->dir_name != NULL &&
2813 !strcmp(base_dir->dir_name, module->dir_name))
2814 print_file_name(fp, module);
2815 }
2816 for (j = 0; j < makefile->nASN1Modules; j++) {
2817 const struct module_struct *module = makefile->ASN1Modules + j;
2818 if (module->dir_name != NULL &&
2819 !strcmp(base_dir->dir_name, module->dir_name))
2820 print_file_name(fp, module);
2821 }
2822 fprintf(fp, "\n"
2823 "\t@echo 'Central directory %s is not up-to-date!'\n"
2824 "\t@exit 2\n\n", base_dir->dir_name);
2825 }
2826 }
2827 } else { /* not central storage */
2828 fprintf(fp, "$(GENERATED_SOURCES) $(GENERATED_HEADERS): compile\n"
2829 "\t@if [ ! -f $@ ]; then %s compile; $(MAKE) compile; fi\n\n"
2830 "check: $(TTCN3_MODULES) ", rm_command);
2831 if (makefile->preprocess) fputs("$(PREPROCESSED_TTCN3_MODULES) ", fp);
2832 fputs("$(ASN1_MODULES)\n"
2833 "\t$(TTCN3_DIR)/bin/compiler -s $(COMPILER_FLAGS) ", fp);
2834 if (makefile->gnu_make) fputs("$^", fp);
2835 else {
2836 fputs("\\\n"
2837 "\t$(TTCN3_MODULES) $(PREPROCESSED_TTCN3_MODULES) $(ASN1_MODULES)",
2838 fp);
2839 }
2840 fputs("\n\n"
2841 "compile: $(TTCN3_MODULES) ", fp);
2842 if (makefile->preprocess) fputs("$(PREPROCESSED_TTCN3_MODULES) ", fp);
2843 fputs("$(ASN1_MODULES)\n"
2844 "\t$(TTCN3_DIR)/bin/compiler $(COMPILER_FLAGS) ", fp);
2845 if (makefile->gnu_make) fputs("$^", fp);
2846 else {
2847 fputs("\\\n"
2848 "\t$(TTCN3_MODULES) ", fp);
2849 if (makefile->preprocess) fputs("$(PREPROCESSED_TTCN3_MODULES) ", fp);
2850 fputs("$(ASN1_MODULES)", fp);
2851 }
2852 fputs(" - $?\n"
2853 "\ttouch $@\n"
2854 "\n", fp);
2855 }
2856 fprintf(fp, "clean:%s\n"
2857 "\t-%s $(EXECUTABLE) $(LIBRARY) $(OBJECTS) $(GENERATED_HEADERS) \\\n"
2858 "\t$(GENERATED_SOURCES) ", add_refd_prjs?" referenced-clean":"", rm_command);
2859 if (makefile->dynamic) fputs("$(SHARED_OBJECTS) ", fp);
2860 if (makefile->preprocess) fputs("$(PREPROCESSED_TTCN3_MODULES) ", fp);
2861 fputs("compile", fp);
2862 if (makefile->central_storage) fputs(" compile-all", fp);
2863 if (makefile->gcc_dep) fputs(" $(DEPFILES)", fp);
2864 fprintf(fp, " \\\n"
2865 "\ttags *.log%s",
2866 add_refd_prjs?" referenced*":"");
2867
2868 fputs("\n\ndep: $(GENERATED_SOURCES) $(USER_SOURCES)",fp);
2869 if (add_refd_prjs) fprintf(fp, "\n\t%s referenced-dep", rm_command);
2870 else fputs(" ;",fp);
2871
2872 if (makefile->gcc_dep) {
2873 fprintf(fp, " \n\n"
2874 "ifeq ($(findstring n,$(MAKEFLAGS)),)\n"
2875 "ifeq ($(filter clean check compile archive diag%s,$(MAKECMDGOALS)),)\n"
2876 "-include $(DEPFILES)\n"
2877 "endif\n"
2878 "endif", (makefile->preprocess ? " preprocess" : ""));
2879 /* Don't include .d files when cleaning etc.; make will try to build them
2880 * and this involves running the Titan compiler. Same for preprocess.
2881 * The check target would be pointless if running the compiler
2882 * without generating code was always preceded by running the compiler
2883 * _and_ generating C++ code. */
2884 }
2885 else { /* old-style dep with makedepend. Do not check compiler version. */
2886 fputs("\n\tmakedepend $(CPPFLAGS) -DMAKEDEPEND_RUN ", fp);
2887 if (makefile->gnu_make) fputs("$^", fp);
2888 else fputs("$(GENERATED_SOURCES) $(USER_SOURCES)", fp);
2889 }
2890 fprintf(fp, "\n\n"
2891 "archive:%s\n"
2892 "\tmkdir -p $(ARCHIVE_DIR)\n"
2893 "\ttar -cvhf - ", add_refd_prjs?" referenced-archive":"");
2894 if (makefile->central_storage) {
2895 fputs("$(TTCN3_MODULES) $(BASE_TTCN3_MODULES) \\\n", fp);
2896 if (makefile->preprocess) {
2897 fputs("\t$(TTCN3_PP_MODULES) $(BASE_TTCN3_PP_MODULES) "
2898 "$(TTCN3_INCLUDES)\\\n", fp);
2899 }
2900 fputs("\t$(ASN1_MODULES) $(BASE_ASN1_MODULES) \\\n"
2901 "\t$(USER_HEADERS) $(BASE_USER_HEADERS) \\\n"
2902 "\t$(USER_SOURCES) $(BASE_USER_SOURCES)", fp);
2903 } else {
2904 fputs("$(TTCN3_MODULES) ", fp);
2905 if (makefile->preprocess) {
2906 fputs("$(TTCN3_PP_MODULES) \\\n"
2907 "\t$(TTCN3_INCLUDES) ", fp);
2908 }
2909 fputs("$(ASN1_MODULES) \\\n"
2910 "\t$(USER_HEADERS) $(USER_SOURCES)", fp);
2911 }
2912 fputs(" $(OTHER_FILES) \\\n"
2913 "\t| gzip >$(ARCHIVE_DIR)/`basename $(TARGET) .exe`-"
2914 "`date '+%y%m%d-%H%M'`.tgz\n\n", fp);
2915
2916 fprintf(fp, "diag:\n"
2917 "\t$(TTCN3_DIR)/bin/compiler -v 2>&1\n"
2918 "\t$(TTCN3_DIR)/bin/mctr_cli -v 2>&1\n"
2919 "\t$(CXX) -v 2>&1\n"
2920 "%s"
2921 "\t@echo TTCN3_DIR=$(TTCN3_DIR)\n"
2922 "\t@echo OPENSSL_DIR=$(OPENSSL_DIR)\n"
2923 "\t@echo XMLDIR=$(XMLDIR)\n"
2924 "\t@echo PLATFORM=$(PLATFORM)\n\n",
2925 makefile->dynamic ? "" : "\t$(AR) -V 2>&1\n");
2926
2927 if (add_refd_prjs) {
2928 fputs("referenced-all referenced-shared_objects referenced-executable referenced-library \\\n"
2929 "referenced-objects referenced-check \\\n"
2930 "referenced-clean referenced-archive:\n"
2931 "\t@for dir in $(REFERENCED_PROJECT_DIRS); do \\\n"
2932 "\t $(MAKE) -C $$dir $(subst referenced-,,$@) || exit; \\\n"
2933 "\tdone; \n\n", fp);
2934 fputs("referenced-dep:\n"
2935 "\t@for dir in $(REFERENCED_PROJECT_DIRS); do \\\n"
2936 "\t $(MAKE) -C $$dir $(subst referenced-,,$@) || exit; \\\n"
2937 "\tdone; \n"
2938 "\ttouch $@\n\n", fp);
2939 }
2940
2941 if (makefile->generatorCommandOutput) {
2942 fputs("### Project specific rules generated by user written script:\n\n", fp);
2943 fputs(makefile->generatorCommandOutput, fp);
2944 fputs("\n### End of project specific rules.\n\n", fp);
2945 }
2946
2947 fputs("#\n"
2948 "# Add your rules here if necessary...\n"
2949 "#\n\n", fp);
2950 fclose(fp);
2951 if (strcmp(makefile->output_file, "Makefile")) {
2952 NOTIFY("Makefile skeleton was written to `%s'.", makefile->output_file);
2953 } else {
2954 NOTIFY("Makefile skeleton was generated.");
2955 }
2956 } else {
2957 ERROR("Output file `%s' already exists. Use switch `-f' to force "
2958 "overwrite.", makefile->output_file);
2959 }
2960 }
2961
2962 #undef COMMENT_PREFIX
2963 #define COMMENT_PREFIX
2964
2965 /** run makefilegen commans for sub-projects */
2966 static void run_makefilegen_commands(struct string2_list* run_command_list)
2967 {
2968 struct string2_list* act_elem = run_command_list;
2969 while (act_elem) {
2970 struct string2_list* next_elem = act_elem->next;
2971 /* run commands if there were no ERRORs */
2972 if ((error_count == 0) && act_elem->str1 && act_elem->str2) {
2973 int rv;
2974 char* sub_proj_effective_work_dir = act_elem->str1;
2975 char* command = act_elem->str2;
2976 char* orig_dir = get_working_dir();
2977 rv = set_working_dir(sub_proj_effective_work_dir);
2978 if (rv) ERROR("Could not set working dir to `%s'", sub_proj_effective_work_dir);
2979 else {
2980 printf("Executing `%s' in working directory `%s'...\n", command, sub_proj_effective_work_dir);
2981 rv = system(command);
2982 if (rv) ERROR("Execution failed with error code %d", rv); // TODO: it's not clear what system()'s return codes can be in different situations and platforms
2983 }
2984 rv = set_working_dir(orig_dir);
2985 if (rv) ERROR("Could not restore working dir to `%s'", orig_dir);
2986 Free(orig_dir);
2987 }
2988 Free(act_elem->str1);
2989 Free(act_elem->str2);
2990 Free(act_elem);
2991 act_elem = next_elem;
2992 }
2993 }
2994
2995 /** create symlinks and delete list */
2996 static void generate_symlinks(struct string2_list* create_symlink_list)
2997 {
2998 struct string2_list* act_elem = create_symlink_list;
2999 while (act_elem) {
3000 struct string2_list* next_elem = act_elem->next;
3001 /* create symlinks if there were no ERRORs */
3002 if ((error_count == 0) && act_elem->str1 && act_elem->str2) {
3003 int fail = symlink(act_elem->str1, act_elem->str2);
3004 if (fail) perror(act_elem->str2); /* complain but do not call ERROR() */
3005 }
3006 Free(act_elem->str1);
3007 Free(act_elem->str2);
3008 Free(act_elem);
3009 act_elem = next_elem;
3010 }
3011 }
3012
3013 /** Performs all tasks of Makefile generation based on the given list of
3014 * modules/files (taken from the command line) and options that represent
3015 * command line switches. */
3016 static void generate_makefile(size_t n_arguments, char *arguments[],
3017 size_t n_other_files, const char *other_files[], const char *output_file,
3018 const char *ets_name, boolean gnu_make, boolean single_mode,
3019 boolean central_storage, boolean absolute_paths, boolean preprocess,
3020 boolean dump_makefile_data, boolean force_overwrite, boolean use_runtime_2,
3021 boolean dynamic, boolean makedepend, boolean coverage,
3022 const char *code_splitting_mode, const char *tcov_file_name,
3023 boolean Lflag, struct string_list* sub_project_dirs, struct string_list* ttcn3_prep_includes,
3024 struct string_list* ttcn3_prep_defines, struct string_list* prep_includes, struct string_list* prep_defines,
3025 boolean codesplittpd, boolean quietly, boolean disablesubtypecheck, const char* cxxcompiler,
3026 const char* optlevel, const char* optflags, boolean disableber, boolean disableraw, boolean disabletext,
3027 boolean disablexer, boolean disablejson, boolean forcexerinasn, boolean defaultasomit, boolean gccmsgformat,
3028 boolean linenumbersonlymsg, boolean includesourceinfo, boolean addsourcelineinfo, boolean suppresswarnings,
3029 boolean outparamboundness, struct string_list* solspeclibraries, struct string_list* sol8speclibraries,
3030 struct string_list* linuxspeclibraries, struct string_list* freebsdspeclibraries,
3031 struct string_list* win32speclibraries, const char* ttcn3preprocessor, struct string_list* linkerlibraries,
3032 struct string_list* additionalObjects, struct string_list* linkerlibsearchpath, char* generatorCommandOutput,
3033 struct string2_list* target_placement_list)
3034 {
3035 size_t i;
3036
3037 struct makefile_struct makefile;
3038 init_makefile_struct(&makefile);
3039
3040 makefile.central_storage = central_storage;
3041 makefile.gnu_make = gnu_make;
3042 makefile.preprocess = preprocess;
3043 makefile.single_mode = single_mode;
3044 makefile.force_overwrite = force_overwrite;
3045 makefile.use_runtime_2 = use_runtime_2;
3046 makefile.dynamic = dynamic;
3047 makefile.gcc_dep = gnu_make && !makedepend;
3048 makefile.coverage = coverage;
3049 makefile.library = Lflag;
3050 makefile.sub_project_dirs = sub_project_dirs;
3051 makefile.ttcn3_prep_includes = ttcn3_prep_includes;
3052 makefile.ttcn3_prep_defines = ttcn3_prep_defines;
3053 makefile.prep_includes = prep_includes;
3054 makefile.prep_defines = prep_defines;
3055 makefile.codesplittpd = codesplittpd;
3056 makefile.quietly = quietly;
3057 makefile.disablesubtypecheck = disablesubtypecheck;
3058 makefile.cxxcompiler = cxxcompiler;
3059 makefile.optlevel = optlevel;
3060 makefile.optflags = optflags;
3061 makefile.disableber = disableber;
3062 makefile.disableraw = disableraw;
3063 makefile.disabletext = disabletext;
3064 makefile.disablexer = disablexer;
3065 makefile.disablejson = disablejson;
3066 makefile.forcexerinasn = forcexerinasn;
3067 makefile.defaultasomit = defaultasomit;
3068 makefile.gccmsgformat = gccmsgformat;
3069 makefile.linenumbersonlymsg = linenumbersonlymsg;
3070 makefile.includesourceinfo = includesourceinfo;
3071 makefile.addsourcelineinfo = addsourcelineinfo;
3072 makefile.suppresswarnings = suppresswarnings;
3073 makefile.outparamboundness = outparamboundness;
3074 makefile.solspeclibraries = solspeclibraries;
3075 makefile.sol8speclibraries = sol8speclibraries;
3076 makefile.linuxspeclibraries = linuxspeclibraries;
3077 makefile.freebsdspeclibraries = freebsdspeclibraries;
3078 makefile.win32speclibraries = win32speclibraries;
3079 makefile.ttcn3preprocessor = ttcn3preprocessor;
3080 makefile.linkerlibraries = linkerlibraries;
3081 makefile.additionalObjects = additionalObjects;
3082 makefile.linkerlibsearchpath = linkerlibsearchpath;
3083 makefile.generatorCommandOutput = generatorCommandOutput;
3084 makefile.target_placement_list = target_placement_list;
3085
3086 for (i = 0; i < n_arguments; i++) {
3087 char *file_name = get_file_name_for_argument(arguments[i]);
3088 if (file_name != NULL) {
3089 FILE *fp = fopen(file_name, "r");
3090 if (fp != NULL) {
3091 char *module_name;
3092 if (is_ttcn3_module(file_name, fp, &module_name)) {
3093 if (is_asn1_module(file_name, fp, NULL)) {
3094 ERROR("File `%s' looks so strange that it can be both ASN.1 and "
3095 "TTCN-3 module. Add it to the Makefile manually.", file_name);
3096 Free(module_name);
3097 } else {
3098 add_ttcn3_module(&makefile, file_name, module_name);
3099 }
3100 } else if (is_asn1_module(file_name, fp, &module_name)) {
3101 if (is_valid_asn1_filename(file_name)) {
3102 add_asn1_module(&makefile, file_name, module_name);
3103 } else {
3104 ERROR("The file name (without suffix) shall be identical to the module name.\n"
3105 "If the name of the ASN.1 module contains a hyphen, the corresponding "
3106 "file name shall contain an underscore character instead.");
3107 }
3108 } else {
3109 add_user_file(&makefile, file_name);
3110 }
3111 fclose(fp);
3112 } else {
3113 ERROR("Cannot open file `%s' for reading: %s", file_name,
3114 strerror(errno));
3115 errno = 0;
3116 }
3117 Free(file_name);
3118 } else if (get_path_status(arguments[i]) == PS_DIRECTORY) {
3119 ERROR("Argument `%s' is a directory.", arguments[i]);
3120 } else {
3121 ERROR("Cannot find any source file for argument `%s'.", arguments[i]);
3122 }
3123 }
3124 for (i = 0; i < n_other_files; i++) {
3125 char *file_name = get_file_name_for_argument(other_files[i]);
3126 if (file_name != NULL) {
3127 add_path_to_list(&makefile.nOtherFiles, &makefile.OtherFiles, file_name,
3128 makefile.working_dir, TRUE);
3129 Free(file_name);
3130 } else if (get_path_status(other_files[i]) == PS_DIRECTORY) {
3131 ERROR("Argument `%s' given as other file is a directory.",
3132 other_files[i]);
3133 } else {
3134 ERROR("Cannot find any other file for argument `%s'.", other_files[i]);
3135 }
3136 }
3137
3138 if (ets_name != NULL) {
3139 char *dir_name = get_dir_name(ets_name, makefile.working_dir);
3140 char *file_name = get_file_from_path(ets_name);
3141 makefile.ets_name = compose_path_name(dir_name, file_name);
3142 Free(dir_name);
3143 Free(file_name);
3144 }
3145
3146 if (code_splitting_mode != NULL) {
3147 makefile.code_splitting_mode = mputprintf(makefile.code_splitting_mode, "-U %s", code_splitting_mode);
3148 }
3149
3150 if (tcov_file_name != NULL) {
3151 makefile.tcov_file_name = mputprintf(makefile.tcov_file_name, "-K %s", tcov_file_name);
3152 }
3153
3154 if (makefile.nTTCN3Modules >= 1) {
3155 if (makefile.ets_name == NULL)
3156 makefile.ets_name = mcopystr(makefile.TTCN3Modules[0].module_name);
3157 } else if (preprocess && (makefile.nTTCN3PPModules >= 1)) {
3158 if (makefile.ets_name == NULL)
3159 makefile.ets_name = mcopystr(makefile.TTCN3PPModules[0].module_name);
3160 } else if (makefile.nASN1Modules >= 1) {
3161 WARNING("No TTCN-3 module was given for the Makefile.");
3162 if (makefile.ets_name == NULL)
3163 makefile.ets_name = mcopystr(makefile.ASN1Modules[0].module_name);
3164 } else if (makefile.nUserFiles > 0) {
3165 WARNING("No TTCN-3 or ASN.1 module was given for the Makefile.");
3166 if (makefile.ets_name == NULL)
3167 makefile.ets_name = mcopystr(makefile.UserFiles[0].file_prefix);
3168 } else {
3169 WARNING("No source files were given for the Makefile");
3170 }
3171
3172 if (output_file != NULL) {
3173 if (get_path_status(output_file) == PS_DIRECTORY)
3174 makefile.output_file = mprintf("%s/Makefile", output_file);
3175 else makefile.output_file = mcopystr(output_file);
3176 } else makefile.output_file = mcopystr("Makefile");
3177 add_path_to_list(&makefile.nOtherFiles, &makefile.OtherFiles,
3178 makefile.output_file, makefile.working_dir, FALSE);
3179
3180 if (preprocess) check_preprocessed_filename_collision(&makefile);
3181 filter_out_generated_files(&makefile);
3182 complete_user_files(&makefile);
3183 if (!absolute_paths) convert_dirs_to_relative(&makefile);
3184 check_special_chars(&makefile);
3185 if (central_storage) collect_base_dirs(&makefile);
3186 check_naming_convention(&makefile);
3187
3188 if (dump_makefile_data) dump_makefile_struct(&makefile, 0);
3189
3190 if (error_count == 0) print_makefile(&makefile);
3191
3192 free_makefile_struct(&makefile);
3193 }
3194
3195 #ifdef COVERAGE_BUILD
3196 #define C_flag "C"
3197 #else
3198 #define C_flag
3199 #endif
3200
3201
3202 static void usage(void)
3203 {
3204 fprintf(stderr, "\n"
3205 "usage: %s [-abc" C_flag "dDfFglLmprRstTVwWX] [-K file] [-P dir]"
3206 " [-U none|type] [-e ets_name] [-o dir|file]\n"
3207 " [-t project_descriptor.tpd [-b buildconfig]]\n"
3208 " [-O file] ... module_name ... testport_name ...\n"
3209 " or %s -v\n"
3210 "\n"
3211 "OPTIONS:\n"
3212 " -a: use absolute pathnames in the generated Makefile\n"
3213 " -c: use the pre-compiled files from central directories\n"
3214 #ifdef COVERAGE_BUILD
3215 " -C: enable coverage of generated C++ code\n"
3216 #endif
3217 " -d: dump the data used for Makefile generation\n"
3218 " -e ets_name: name of the target executable\n"
3219 " -f: force overwriting of the output Makefile\n"
3220 " -g: generate Makefile for use with GNU make\n"
3221 " -l: use dynamic linking\n"
3222 " -L: create makefile with library archive as the default target\n"
3223 " -m: always use makedepend for dependencies\n"
3224 " -K file: enable selective code coverage\n"
3225 " -o dir|file: write the Makefile to the given directory or file\n"
3226 " -O file: add the given file to the Makefile as other file\n"
3227 " -p: generate Makefile with TTCN-3 preprocessing\n"
3228 " -R: use function test runtime (TITAN_RUNTIME_2)\n"
3229 " -s: generate Makefile for single mode\n"
3230 " -U none|type: split generated code\n"
3231 " -v: show version\n"
3232 " -w: suppress warnings\n"
3233 " -Y: Enforces legacy behaviour of the \"out\" function parameters (see refguide)\n"
3234 "Options for processing the Titan Project Descriptor file(s):\n"
3235 " -t tpd: read project descriptor file\n"
3236 " -b buildconfig: use the specified build config instead of the default\n"
3237 " -D: use current directory as working directory\n"
3238 " -V: disable validation of TPD file with schema\n"
3239 " -r: generate Makefile hierarchy for TPD hierarchy (recursive)\n"
3240 " -F: force overwriting of all generated Makefiles, use with -r\n"
3241 " -T: generate only top-level Makefile of the hierarchy, use with -r\n"
3242 " -P dir: prints out a file list found in a given TPD relative to the given directory\n"
3243 " -X: generate XML file that describes the TPD hierarchy, use with -r\n"
3244 " -W: prefix working directories with project name\n"
3245 , program_name, program_name);
3246 }
3247
3248 #define SET_FLAG(x) if (x##flag) {\
3249 ERROR("Flag -" #x " was specified more than once.");\
3250 error_flag = TRUE;\
3251 } else x##flag = TRUE
3252
3253 void free_string_list(struct string_list* act_elem)
3254 {
3255 while (act_elem) {
3256 struct string_list* next_elem = act_elem->next;
3257 Free(act_elem->str);
3258 Free(act_elem);
3259 act_elem = next_elem;
3260 }
3261 }
3262
3263 void free_string2_list(struct string2_list* act_elem)
3264 {
3265 while (act_elem) {
3266 struct string2_list* next_elem = act_elem->next;
3267 Free(act_elem->str1);
3268 Free(act_elem->str2);
3269 Free(act_elem);
3270 act_elem = next_elem;
3271 }
3272 }
3273
3274 int main(int argc, char *argv[])
3275 {
3276 boolean
3277 aflag = FALSE, bflag = FALSE, cflag = FALSE, Cflag = FALSE,
3278 dflag = FALSE, eflag = FALSE, fflag = FALSE, gflag = FALSE,
3279 oflag = FALSE, Kflag = FALSE, lflag = FALSE, pflag = FALSE,
3280 Pflag = FALSE, Rflag = FALSE, sflag = FALSE, tflag = FALSE,
3281 wflag = FALSE, vflag = FALSE, mflag = FALSE, Uflag = FALSE,
3282 Lflag = FALSE, rflag = FALSE, Fflag = FALSE, Xflag = FALSE,
3283 Tflag = FALSE, Yflag = FALSE, csflag = FALSE, quflag = FALSE,
3284 dsflag = FALSE, dbflag = FALSE, drflag = FALSE, dtflag = FALSE,
3285 dxflag = FALSE, fxflag = FALSE, doflag = FALSE,
3286 gfflag = FALSE, lnflag = FALSE, isflag = FALSE, asflag = FALSE,
3287 swflag = FALSE, Vflag = FALSE, Dflag = FALSE, Wflag = FALSE,
3288 djflag = FALSE;
3289 boolean error_flag = FALSE;
3290 char *output_file = NULL;
3291 char *ets_name = NULL;
3292 size_t n_other_files = 0;
3293 const char **other_files = NULL;
3294 const char *code_splitting_mode = NULL;
3295 const char *tpd_file_name = NULL;
3296 const char *tpd_build_config = NULL;
3297 const char *tcov_file_name = NULL;
3298 const char *file_list_path = NULL;
3299 enum tpd_result tpd_processed = FALSE;
3300 struct string_list* sub_project_dirs = NULL;
3301 struct string2_list* create_symlink_list = NULL;
3302 struct string_list* ttcn3_prep_includes = NULL;
3303 struct string_list* ttcn3_prep_defines = NULL;
3304 struct string_list* prep_includes = NULL;
3305 struct string_list* prep_defines = NULL;
3306 char *cxxcompiler = NULL;
3307 char *optlevel = NULL;
3308 char *optflags = NULL;
3309 struct string_list* solspeclibraries = NULL;
3310 struct string_list* sol8speclibraries = NULL;
3311 struct string_list* linuxspeclibraries = NULL;
3312 struct string_list* freebsdspeclibraries = NULL;
3313 struct string_list* win32speclibraries = NULL;
3314 char *ttcn3prep = NULL;
3315 struct string_list* linkerlibraries = NULL;
3316 struct string_list* additionalObjects = NULL;
3317 struct string_list* linkerlibsearchpath = NULL;
3318 char* generatorCommandOutput = NULL;
3319 struct string2_list* target_placement_list = NULL;
3320 struct string2_list* run_command_list = NULL;
3321
3322 #ifdef LICENSE
3323 license_struct lstr;
3324 int valid_license;
3325 #endif
3326
3327 program_name = argv[0];
3328
3329 if (argc == 1) {
3330 fputs("Makefile Generator for the TTCN-3 Test Executor, version "
3331 PRODUCT_NUMBER "\n", stderr);
3332 usage();
3333 return EXIT_FAILURE;
3334 }
3335
3336 for ( ; ; ) {
3337 int c = getopt(argc, argv, "O:ab:c" C_flag "dDe:fFgK:o:lLmpP:rRst:TU:vVwWXY");
3338 if (c == -1) break;
3339 switch (c) {
3340 case 'O':
3341 n_other_files++;
3342 other_files = (const char**)
3343 Realloc(other_files, n_other_files * sizeof(*other_files));
3344 other_files[n_other_files - 1] = optarg;
3345 break;
3346 case 'a':
3347 SET_FLAG(a);
3348 break;
3349 case 'b':
3350 SET_FLAG(b);
3351 tpd_build_config = optarg;
3352 break;
3353 case 'c':
3354 SET_FLAG(c);
3355 break;
3356 case 'K':
3357 SET_FLAG(K);
3358 tcov_file_name = optarg;
3359 break;
3360 #ifdef COVERAGE_BUILD
3361 case 'C':
3362 SET_FLAG(C);
3363 break;
3364 #endif
3365 case 'd':
3366 SET_FLAG(d);
3367 break;
3368 case 'D':
3369 SET_FLAG(D);
3370 break;
3371 case 'e':
3372 SET_FLAG(e);
3373 ets_name = optarg;
3374 break;
3375 case 'f':
3376 SET_FLAG(f);
3377 break;
3378 case 'F':
3379 SET_FLAG(F);
3380 break;
3381 case 'g':
3382 SET_FLAG(g);
3383 break;
3384 case 'o':
3385 SET_FLAG(o);
3386 output_file = optarg;
3387 break;
3388 case 'l':
3389 SET_FLAG(l);
3390 break;
3391 case 'L':
3392 SET_FLAG(L);
3393 break;
3394 case 'm':
3395 SET_FLAG(m);
3396 break;
3397 case 'p':
3398 SET_FLAG(p);
3399 break;
3400 case 'P':
3401 SET_FLAG(P);
3402 /* Optional arguments with `::' are GNU specific... */
3403 if (get_path_status(optarg) == PS_DIRECTORY) {
3404 file_list_path = optarg;
3405 } else {
3406 ERROR("The -P flag requires a valid directory as its argument "
3407 "instead of `%s'", optarg);
3408 error_flag = TRUE;
3409 }
3410 break;
3411 case 'r':
3412 SET_FLAG(r);
3413 break;
3414 case 'R':
3415 SET_FLAG(R);
3416 break;
3417 case 's':
3418 SET_FLAG(s);
3419 break;
3420 case 't':
3421 SET_FLAG(t);
3422 tpd_file_name = optarg;
3423 break;
3424 case 'T':
3425 SET_FLAG(T);
3426 break;
3427 case 'Y':
3428 SET_FLAG(Y);
3429 break;
3430 case 'U':
3431 SET_FLAG(U);
3432 code_splitting_mode = optarg;
3433 if (strcmp(optarg, "none") != 0 &&
3434 strcmp(optarg, "type") != 0)
3435 ERROR("Unrecognizable argument: '%s'. Valid options for -U switch are: "
3436 "'none', 'type'", optarg);
3437 break;
3438 case 'v':
3439 SET_FLAG(v);
3440 break;
3441 case 'V':
3442 SET_FLAG(V);
3443 break;
3444 case 'w':
3445 SET_FLAG(w);
3446 suppress_warnings = TRUE;
3447 break;
3448 case 'W':
3449 SET_FLAG(W);
3450 break;
3451 case 'X':
3452 SET_FLAG(X);
3453 break;
3454 default:
3455 error_flag = TRUE;
3456 break;
3457 }
3458 }
3459
3460 /* Checking incompatible options */
3461 if (vflag) {
3462 /* -v prints the version and exits, it's pointless to specify other flags */
3463 if ( aflag || bflag || cflag || Cflag || dflag || eflag || fflag || Fflag || gflag
3464 || mflag || oflag || lflag || pflag || Pflag || rflag || Rflag || sflag
3465 || tflag || Tflag || Vflag || wflag || Xflag || Kflag || Dflag || Wflag || Yflag
3466 || n_other_files > 0)
3467 error_flag = TRUE;
3468 }
3469
3470 if ((bflag || Dflag || Pflag || Vflag || rflag || Wflag) && !tflag) {
3471 ERROR("Using the '-b', '-D', '-P', '-V', '-r' or '-W' option requires the use of the -t' option.");
3472 error_flag = TRUE;
3473 }
3474
3475 if (rflag && !cflag) {
3476 ERROR("Using the '-r' option requires use of the '-c' option. Recursive makefile hierarchy uses the central directory feature.");
3477 error_flag = TRUE;
3478 }
3479
3480 if (Fflag && !rflag) {
3481 ERROR("Using the '-F' option requires use of the '-r' option.");
3482 error_flag = TRUE;
3483 }
3484
3485 if (Xflag && !rflag) {
3486 ERROR("Using the '-X' option requires use of the '-r' option.");
3487 error_flag = TRUE;
3488 }
3489
3490 if (Tflag && !rflag) {
3491 ERROR("Using the '-T' option requires use of the '-r' option.");
3492 error_flag = TRUE;
3493 }
3494
3495 if (lflag && !strncmp(get_platform_string(), "WIN32", 5)) {
3496 ERROR("Generating Makefile with dynamic linking enabled is not supported "
3497 "on Windows platform");
3498 error_flag = TRUE;
3499 }
3500
3501 if (error_flag) {
3502 usage();
3503 return EXIT_FAILURE;
3504 }
3505
3506 if (vflag) {
3507 fputs("Makefile Generator for the TTCN-3 Test Executor\n"
3508 "Product number: " PRODUCT_NUMBER "\n"
3509 "Build date: " __DATE__ " " __TIME__ "\n"
3510 "Compiled with: " C_COMPILER_VERSION "\n\n"
3511 COPYRIGHT_STRING "\n\n", stderr);
3512 #ifdef LICENSE
3513 print_license_info();
3514 #endif
3515 return EXIT_SUCCESS;
3516 }
3517
3518 #ifdef LICENSE
3519 init_openssl();
3520 load_license(&lstr);
3521 valid_license = verify_license(&lstr);
3522 free_openssl();
3523 if (!valid_license) {
3524 free_license(&lstr);
3525 exit(EXIT_FAILURE);
3526 }
3527 if (!check_feature(&lstr, FEATURE_TPGEN)) {
3528 ERROR("The license key does not allow the generation of "
3529 "Makefile skeletons.");
3530 return EXIT_FAILURE;
3531 }
3532 free_license(&lstr);
3533 #endif
3534
3535 if (tflag) {
3536 char* abs_work_dir = NULL;
3537 FILE* prj_graph_fp = NULL;
3538 sub_project_dirs = (struct string_list*)Malloc(sizeof(struct string_list));
3539 sub_project_dirs->str = NULL;
3540 sub_project_dirs->next = NULL;
3541 ttcn3_prep_includes = (struct string_list*)Malloc(sizeof(struct string_list));
3542 ttcn3_prep_includes->str = NULL;
3543 ttcn3_prep_includes->next = NULL;
3544 ttcn3_prep_defines = (struct string_list*)Malloc(sizeof(struct string_list));
3545 ttcn3_prep_defines->str = NULL;
3546 ttcn3_prep_defines->next = NULL;
3547 prep_includes = (struct string_list*)Malloc(sizeof(struct string_list));
3548 prep_includes->str = NULL;
3549 prep_includes->next = NULL;
3550 prep_defines = (struct string_list*)Malloc(sizeof(struct string_list));
3551 prep_defines->str = NULL;
3552 prep_defines->next = NULL;
3553 solspeclibraries = (struct string_list*)Malloc(sizeof(struct string_list));
3554 solspeclibraries->str = NULL;
3555 solspeclibraries->next = NULL;
3556 sol8speclibraries = (struct string_list*)Malloc(sizeof(struct string_list));
3557 sol8speclibraries->str = NULL;
3558 sol8speclibraries->next = NULL;
3559 linuxspeclibraries = (struct string_list*)Malloc(sizeof(struct string_list));
3560 linuxspeclibraries->str = NULL;
3561 linuxspeclibraries->next = NULL;
3562 freebsdspeclibraries = (struct string_list*)Malloc(sizeof(struct string_list));
3563 freebsdspeclibraries->str = NULL;
3564 freebsdspeclibraries->next = NULL;
3565 win32speclibraries = (struct string_list*)Malloc(sizeof(struct string_list));
3566 win32speclibraries->str = NULL;
3567 win32speclibraries->next = NULL;
3568 linkerlibraries = (struct string_list*)Malloc(sizeof(struct string_list));
3569 linkerlibraries->str = NULL;
3570 linkerlibraries->next = NULL;
3571 additionalObjects = (struct string_list*)Malloc(sizeof(struct string_list));
3572 additionalObjects->str = NULL;
3573 additionalObjects->next = NULL;
3574 linkerlibsearchpath = (struct string_list*)Malloc(sizeof(struct string_list));
3575 linkerlibsearchpath->str = NULL;
3576 linkerlibsearchpath->next = NULL;
3577
3578 if (Xflag) {
3579 const char* prj_graph_filename = "project_hierarchy_graph.xml";
3580 prj_graph_fp = fopen(prj_graph_filename, "w");
3581 if (prj_graph_fp==NULL) WARNING("Cannot open output file `%s' for writing: %s", prj_graph_filename, strerror(errno));
3582 if (prj_graph_fp) fprintf(prj_graph_fp, "<project_hierarchy_graph top_level_tpd=\"%s\">\n", tpd_file_name);
3583 }
3584 create_symlink_list = (struct string2_list*)Malloc(sizeof(struct string2_list));
3585 create_symlink_list->str1 = NULL;
3586 create_symlink_list->str2 = NULL;
3587 create_symlink_list->next = NULL;
3588 target_placement_list = (struct string2_list*)Malloc(sizeof(struct string2_list));
3589 target_placement_list->str1 = NULL;
3590 target_placement_list->str2 = NULL;
3591 target_placement_list->next = NULL;
3592 run_command_list = (struct string2_list*)Malloc(sizeof(struct string2_list));
3593 run_command_list->str1 = NULL;
3594 run_command_list->str2 = NULL;
3595 run_command_list->next = NULL;
3596 tpd_processed = process_tpd(tpd_file_name, tpd_build_config, file_list_path,
3597 &argc, &argv, &optind, &ets_name,
3598 &gflag, &sflag, &cflag, &aflag, &pflag,
3599 &Rflag, &lflag, &mflag, &Pflag, &Lflag, rflag, Fflag, Tflag, output_file, &abs_work_dir, sub_project_dirs, program_name, prj_graph_fp,
3600 create_symlink_list,ttcn3_prep_includes, ttcn3_prep_defines, prep_includes, prep_defines, &csflag, &quflag, &dsflag, &cxxcompiler,
3601 &optlevel, &optflags, &dbflag, &drflag, &dtflag, &dxflag, &djflag, &fxflag, &doflag, &gfflag, &lnflag, &isflag,
3602 &asflag, &swflag, &Yflag, solspeclibraries, sol8speclibraries, linuxspeclibraries, freebsdspeclibraries, win32speclibraries, &ttcn3prep,
3603 linkerlibraries, additionalObjects, linkerlibsearchpath, Vflag, Dflag, &generatorCommandOutput, target_placement_list, Wflag, run_command_list);
3604 Free(abs_work_dir);
3605 if (prj_graph_fp) {
3606 fprintf(prj_graph_fp, "</project_hierarchy_graph>\n");
3607 fclose(prj_graph_fp);
3608 }
3609 if (tpd_processed == TPD_FAILED) ERROR("Failed to process %s", tpd_file_name);
3610 }
3611
3612 if (!Pflag) {
3613 run_makefilegen_commands(run_command_list);
3614 generate_symlinks(create_symlink_list);
3615 generate_makefile(argc - optind, argv + optind, n_other_files, other_files,
3616 output_file, ets_name, gflag, sflag, cflag, aflag, pflag, dflag, fflag||Fflag,
3617 Rflag, lflag, mflag, Cflag, code_splitting_mode, tcov_file_name, Lflag, rflag ? sub_project_dirs : NULL, ttcn3_prep_includes,
3618 ttcn3_prep_defines, prep_includes, prep_defines, csflag, quflag, dsflag, cxxcompiler, optlevel, optflags, dbflag,
3619 drflag, dtflag, dxflag, djflag, fxflag, doflag, gfflag, lnflag, isflag, asflag, swflag, Yflag, solspeclibraries,
3620 sol8speclibraries, linuxspeclibraries, freebsdspeclibraries, win32speclibraries, ttcn3prep, linkerlibraries, additionalObjects,
3621 linkerlibsearchpath, generatorCommandOutput, target_placement_list);
3622 }
3623
3624 free_string_list(sub_project_dirs);
3625 free_string_list(ttcn3_prep_includes);
3626 free_string_list(ttcn3_prep_defines);
3627 free_string_list(prep_includes);
3628 free_string_list(prep_defines);
3629 free_string_list(solspeclibraries);
3630 free_string_list(sol8speclibraries);
3631 free_string_list(linuxspeclibraries);
3632 free_string_list(freebsdspeclibraries);
3633 free_string_list(win32speclibraries);
3634 free_string_list(linkerlibraries);
3635 free_string_list(additionalObjects);
3636 free_string_list(linkerlibsearchpath);
3637
3638 Free(generatorCommandOutput);
3639 free_string2_list(target_placement_list);
3640
3641 Free(other_files);
3642 if (tpd_processed == TPD_SUCCESS) {
3643 int E;
3644 if (!(eflag && ets_name))
3645 Free(ets_name);
3646 if (cxxcompiler)
3647 Free(cxxcompiler);
3648 if (optlevel)
3649 Free(optlevel);
3650 if (optflags)
3651 Free(optflags);
3652 if (ttcn3prep)
3653 Free(ttcn3prep);
3654 /* Free(output_file); */
3655 for (E = 0; E < argc; ++E) Free(argv[E]);
3656 Free(argv);
3657 }
3658 /* check_mem_leak(program_name); not needed when linked to new.cc */
3659 return error_count > 0 ? EXIT_FAILURE : EXIT_SUCCESS;
3660 }
3661
3662
This page took 0.486884 seconds and 5 git commands to generate.