makefile.c 221 KB
Newer Older
Elemer Lelik's avatar
Elemer Lelik committed
1
/******************************************************************************
balaskoa's avatar
balaskoa committed
2
 * Copyright (c) 2000-2020 Ericsson Telecom AB
Elemer Lelik's avatar
Elemer Lelik committed
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v2.0
Elemer Lelik's avatar
Elemer Lelik committed
5
 * which accompanies this distribution, and is available at
6
 * https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.html
Elemer Lelik's avatar
Elemer Lelik committed
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
 *
 * Contributors:
 *   
 *   >
 *   Baji, Laszlo
 *   Balasko, Jeno
 *   Baranyi, Botond
 *   Beres, Szabolcs
 *   Delic, Adam
 *   Forstner, Matyas
 *   Koppany, Csaba
 *   Kovacs, Ferenc
 *   Kremer, Peter
 *   Lovassy, Arpad
 *   Pandi, Krisztian
 *   Raduly, Csaba
 *   Szabados, Kristof
 *   Szabo, Bence Janos
 *   Szabo, Janos Zoltan – initial implementation
 *   Szalay, Akos
 *   Zalanyi, Balazs Andor
 *   Pandi, Krisztian
 *
 ******************************************************************************/
Elemer Lelik's avatar
Elemer Lelik committed
31
32
33
34
35
36
37
38
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <unistd.h>
#include <errno.h>
#include <ctype.h>
#if defined SOLARIS || defined SOLARIS8
Elemer Lelik's avatar
Elemer Lelik committed
39
#include <sys/utsname.h>
Elemer Lelik's avatar
Elemer Lelik committed
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
#endif

#include "../common/memory.h"
#include "../common/path.h"
#include "../common/version_internal.h"
#include "../common/userinfo.h"
#include "ttcn3/ttcn3_preparser.h"
#include "asn1/asn1_preparser.h"

#ifdef LICENSE
#include "../common/license.h"
#endif

#include "xpather.h"

static const char *program_name = NULL;
static unsigned int error_count = 0;
static boolean suppress_warnings = FALSE;
Elemer Lelik's avatar
Elemer Lelik committed
58
59
void free_string2_list(struct string2_list* act_elem);
void free_string_list(struct string_list* act_elem);
Elemer Lelik's avatar
Elemer Lelik committed
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
void ERROR(const char *fmt, ...)
{
  va_list parameters;
  fprintf(stderr, "%s: error: ", program_name);
  va_start(parameters, fmt);
  vfprintf(stderr, fmt, parameters);
  va_end(parameters);
  fprintf(stderr, "\n");
  fflush(stderr);
  error_count++;
}

void WARNING(const char *fmt, ...)
{
  va_list parameters;
  if (suppress_warnings) return;
  fprintf(stderr, "%s: warning: ", program_name);
  va_start(parameters, fmt);
  vfprintf(stderr, fmt, parameters);
  va_end(parameters);
  putc('\n', stderr);
  fflush(stderr);
}

void NOTIFY(const char *fmt, ...)
{
  va_list parameters;
  va_start(parameters, fmt);
  vfprintf(stderr, fmt, parameters);
  va_end(parameters);
  putc('\n', stderr);
  fflush(stderr);
}

void DEBUG(unsigned level, const char *fmt, ...)
{
  va_list parameters;
  fprintf(stderr, "%*s", 2 * level, "");
  va_start(parameters, fmt);
  vfprintf(stderr, fmt, parameters);
  va_end(parameters);
  putc('\n', stderr);
  fflush(stderr);
}

void path_error(const char *fmt, ...)
{
  va_list ap;
  char *err_msg;
  va_start(ap, fmt);
  err_msg = mprintf_va_list(fmt, ap);
  va_end(ap);
  ERROR("%s", err_msg);
  Free(err_msg);
}


#if defined SOLARIS || defined SOLARIS8
/** Automatic detection of Solaris version based on uname() system call.
 * Distinguishing is needed because some socket functions use socklen_t
 * (which is an alias for unsigned int) as length arguments on Solaris 8.
 * On Solaris 2.6 the argument type is simply int and no socklen_t or other
 * alias exists.
 * Note: It was discovered later that Solaris 7 (which is used rarely within
 * Ericsson) already uses socklen_t thus the SOLARIS8 platform identifier is a
 * bit misleading. */
static const char *get_platform_string(void)
{
    struct utsname name;
    int major, minor;
    if (uname(&name) < 0) {
	WARNING("System call uname() failed: %s", strerror(errno));
	errno = 0;
	return "SOLARIS";
    }
    if (sscanf(name.release, "%d.%d", &major, &minor) == 2 && major == 5) {
	if (minor <= 6) return "SOLARIS";
	else return "SOLARIS8";
    } else {
	ERROR("Invalid OS release: %s", name.release);
	return "SOLARIS";
    }
}
#elif defined LINUX
#define get_platform_string() "LINUX"
#elif defined FREEBSD
#define get_platform_string() "FREEBSD"
#elif defined WIN32
#define get_platform_string() "WIN32"
#elif defined INTERIX
#define get_platform_string() "INTERIX"
#else
#error Platform was not set.
#endif

/** structure for describing TTCN-3 and ASN.1 modules */
struct module_struct {
  char *dir_name; /* directory of the TTCN-3 or ASN.1 file, it is NULL if the
		     file is in the current working directory */
  char *file_name; /* name of the TTCN-3 or ASN.1 file */
  char *module_name; /* name of the TTCN-3 or ASN.1 module */
  boolean is_regular; /* indicates whether the name of the source file follows
			 the default naming convention */
};

/** structure for describing test ports and other C/C++ modules */
struct user_struct {
  char *dir_name; /* directory of the C/C++ source files, it is NULL if the
		     files are in the current working directory */
  char *file_prefix; /* the common prefix of the header and source file */
  char *header_name; /* name of the C/C++ header file, which has .hh or .h or .hpp
			suffix, it is NULL if there is no header file */
  char *source_name; /* name of the C/C++ source file, which has .cc or .c or .cpp
			suffix, it is NULL if there is no source file */
  boolean has_hh_suffix; /* indicates whether the header file is present and
			    has .hh or .hpp suffix */
  boolean has_cc_suffix; /* indicates whether the source file is present and
			    has .cc or .cpp suffix */
};

/** structure for directories that pre-compiled files are taken from */
struct base_dir_struct {
  const char *dir_name; /* name of the directory */
  boolean has_modules; /* indicates whether there are TTCN-3/ASN.1 modules in
			  the directory (it is set to FALSE if dir_name
			  contains user C/C++ files only */
};

/** data structure that describes the information needed for the Makefile */
struct makefile_struct {
Elemer Lelik's avatar
Elemer Lelik committed
190
  char *project_name;
Elemer Lelik's avatar
Elemer Lelik committed
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
  size_t nTTCN3Modules;
  struct module_struct *TTCN3Modules;

  boolean preprocess;
  size_t nTTCN3PPModules;
  struct module_struct *TTCN3PPModules;

  boolean TTCN3ModulesRegular;
  boolean BaseTTCN3ModulesRegular;
  size_t nTTCN3IncludeFiles;
  char **TTCN3IncludeFiles;

  size_t nASN1Modules;
  struct module_struct *ASN1Modules;
  boolean ASN1ModulesRegular;
  boolean BaseASN1ModulesRegular;
207
208
209
210
  
  size_t nXSDModules;
  struct module_struct *XSDModules;
  // No XSDModulesRegular and BaseXSDModulesRegular: it would be always false
Elemer Lelik's avatar
Elemer Lelik committed
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236

  size_t nUserFiles;
  struct user_struct *UserFiles;
  boolean UserHeadersRegular;
  boolean UserSourcesRegular;
  boolean BaseUserHeadersRegular;
  boolean BaseUserSourcesRegular;

  size_t nOtherFiles;
  char **OtherFiles;

  boolean central_storage;
  size_t nBaseDirs;
  struct base_dir_struct *BaseDirs;
  char *working_dir;
  boolean gnu_make;
  boolean single_mode;
  char *output_file;
  char *ets_name;
  boolean force_overwrite;
  boolean use_runtime_2;
  boolean dynamic;
  boolean gcc_dep;
  char *code_splitting_mode;
  boolean coverage;
  char *tcov_file_name;
Elemer Lelik's avatar
Elemer Lelik committed
237
  struct string_list* profiled_file_list; /* not owned */
Elemer Lelik's avatar
Elemer Lelik committed
238
  boolean library;
Elemer Lelik's avatar
Elemer Lelik committed
239
240
  boolean linkingStrategy;
  boolean hierarchical;
Elemer Lelik's avatar
Elemer Lelik committed
241
242
243
  struct string_list* sub_project_dirs; /* not owned */
  struct string_list* ttcn3_prep_includes; /* not owned */
  struct string_list* ttcn3_prep_defines; /* not owned */
Elemer Lelik's avatar
Elemer Lelik committed
244
  struct string_list* ttcn3_prep_undefines; /* not owned */
Elemer Lelik's avatar
Elemer Lelik committed
245
246
  struct string_list* prep_includes; /* not owned */
  struct string_list* prep_defines; /* not owned */
Elemer Lelik's avatar
Elemer Lelik committed
247
  struct string_list* prep_undefines; /* not owned */
248
  const char *codesplittpd;
Elemer Lelik's avatar
Elemer Lelik committed
249
250
251
252
253
  boolean quietly;
  boolean disablesubtypecheck;
  const char *cxxcompiler;
  const char *optlevel;
  const char *optflags;
254
  const char* linkerOptions;
255
256
  boolean semanticcheckonly;
  boolean disableattibutevalidation;
Elemer Lelik's avatar
Elemer Lelik committed
257
258
259
260
261
  boolean disableber;
  boolean disableraw;
  boolean disabletext;
  boolean disablexer;
  boolean disablejson;
262
  boolean disableoer;
Elemer Lelik's avatar
Elemer Lelik committed
263
264
265
266
267
268
269
270
  boolean forcexerinasn;
  boolean defaultasomit;
  boolean gccmsgformat;
  boolean linenumbersonlymsg;
  boolean includesourceinfo;
  boolean addsourcelineinfo;
  boolean suppresswarnings;
  boolean outparamboundness;
Elemer Lelik's avatar
Elemer Lelik committed
271
  boolean omit_in_value_list;
Elemer Lelik's avatar
Elemer Lelik committed
272
  boolean warnings_for_bad_variants;
273
  boolean activate_debugger;
274
  boolean ignore_untagged_on_top_union;
Elemer Lelik's avatar
Elemer Lelik committed
275
  boolean disable_predef_ext_folder;
276
  boolean enable_legacy_encoding;
277
  boolean disable_userinfo;
278
  boolean realtime_features;
279
  boolean oop_features;
280
  boolean charstring_compat;
Elemer Lelik's avatar
Elemer Lelik committed
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
  struct string_list* solspeclibraries; /* not owned */
  struct string_list* sol8speclibraries; /* not owned */
  struct string_list* linuxspeclibraries; /* not owned */
  struct string_list* freebsdspeclibraries; /* not owned */
  struct string_list* win32speclibraries; /* not owned */
  const char *ttcn3preprocessor;
  struct string_list* linkerlibraries; /* not owned */
  struct string_list* additionalObjects; /* not owned */
  struct string_list* linkerlibsearchpath; /* not owned */
  char* generatorCommandOutput; /* not owned */
  struct string2_list* target_placement_list; /* not owned */
};

/** Initializes structure \a makefile with empty lists and default settings. */
static void init_makefile_struct(struct makefile_struct *makefile)
{
Elemer Lelik's avatar
Elemer Lelik committed
297
  makefile->project_name = NULL;
Elemer Lelik's avatar
Elemer Lelik committed
298
299
300
301
302
303
304
305
306
307
308
309
310
  makefile->nTTCN3Modules = 0;
  makefile->TTCN3Modules = NULL;
  makefile->preprocess = FALSE;
  makefile->nTTCN3PPModules = 0;
  makefile->TTCN3PPModules = NULL;
  makefile->TTCN3ModulesRegular = TRUE;
  makefile->BaseTTCN3ModulesRegular = TRUE;
  makefile->nTTCN3IncludeFiles = 0;
  makefile->TTCN3IncludeFiles = NULL;
  makefile->nASN1Modules = 0;
  makefile->ASN1Modules = NULL;
  makefile->ASN1ModulesRegular = TRUE;
  makefile->BaseASN1ModulesRegular = TRUE;
311
312
  makefile->nXSDModules = 0;
  makefile->XSDModules = NULL;
Elemer Lelik's avatar
Elemer Lelik committed
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
  makefile->nUserFiles = 0;
  makefile->UserFiles = NULL;
  makefile->UserHeadersRegular = TRUE;
  makefile->UserSourcesRegular = TRUE;
  makefile->BaseUserHeadersRegular = TRUE;
  makefile->BaseUserSourcesRegular = TRUE;
  makefile->nOtherFiles = 0;
  makefile->OtherFiles = NULL;
  makefile->central_storage = FALSE;
  makefile->nBaseDirs = 0;
  makefile->BaseDirs = NULL;
  makefile->working_dir = get_working_dir();
  makefile->gnu_make = FALSE;
  makefile->single_mode = FALSE;
  makefile->ets_name = NULL;
  makefile->output_file = NULL;
  makefile->force_overwrite = FALSE;
  makefile->use_runtime_2 = FALSE;
  makefile->dynamic = FALSE;
  makefile->gcc_dep = FALSE;
  makefile->code_splitting_mode = NULL;
  makefile->coverage = FALSE;
  makefile->tcov_file_name = NULL;
Elemer Lelik's avatar
Elemer Lelik committed
336
  makefile->profiled_file_list = NULL;
Elemer Lelik's avatar
Elemer Lelik committed
337
  makefile->library = FALSE;
Elemer Lelik's avatar
Elemer Lelik committed
338
339
  makefile->linkingStrategy = FALSE;
  makefile->hierarchical = FALSE;
Elemer Lelik's avatar
Elemer Lelik committed
340
341
342
343
344
  makefile->sub_project_dirs = NULL;
  makefile->ttcn3_prep_includes = NULL;
  makefile->prep_includes = NULL;
  makefile->prep_defines = NULL;
  makefile->outparamboundness = FALSE;
Elemer Lelik's avatar
Elemer Lelik committed
345
  makefile->omit_in_value_list = FALSE;
Elemer Lelik's avatar
Elemer Lelik committed
346
  makefile->warnings_for_bad_variants = FALSE;
347
  makefile->activate_debugger = FALSE;
348
349
  makefile->ignore_untagged_on_top_union = FALSE;
  makefile->disable_predef_ext_folder = FALSE;
350
  makefile->enable_legacy_encoding = FALSE;
351
  makefile->disable_userinfo = FALSE;
352
  makefile->realtime_features = FALSE;
353
  makefile->oop_features = FALSE;
354
  makefile->charstring_compat = FALSE;
Elemer Lelik's avatar
Elemer Lelik committed
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
  makefile->solspeclibraries = NULL;
  makefile->sol8speclibraries = NULL;
  makefile->linuxspeclibraries = NULL;
  makefile->freebsdspeclibraries = NULL;
  makefile->win32speclibraries = NULL;
  makefile->linkerlibraries = NULL;
  makefile->additionalObjects = NULL;
  makefile->linkerlibsearchpath = NULL;
  makefile->generatorCommandOutput = NULL;
  makefile->target_placement_list = NULL;
}

/** Deallocates all memory associated with structure \a makefile. */
static void free_makefile_struct(const struct makefile_struct *makefile)
{
Elemer Lelik's avatar
Elemer Lelik committed
370
  Free(makefile->project_name);
Elemer Lelik's avatar
Elemer Lelik committed
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
  size_t i;
  for (i = 0; i < makefile->nTTCN3Modules; i++) {
    Free(makefile->TTCN3Modules[i].dir_name);
    Free(makefile->TTCN3Modules[i].file_name);
    Free(makefile->TTCN3Modules[i].module_name);
  }
  Free(makefile->TTCN3Modules);
  for (i = 0; i < makefile->nTTCN3PPModules; i++) {
    Free(makefile->TTCN3PPModules[i].dir_name);
    Free(makefile->TTCN3PPModules[i].file_name);
    Free(makefile->TTCN3PPModules[i].module_name);
  }
  Free(makefile->TTCN3PPModules);
  for (i = 0; i < makefile->nTTCN3IncludeFiles; i++)
    Free(makefile->TTCN3IncludeFiles[i]);
  Free(makefile->TTCN3IncludeFiles);
  for (i = 0; i < makefile->nASN1Modules; i++) {
    Free(makefile->ASN1Modules[i].dir_name);
    Free(makefile->ASN1Modules[i].file_name);
    Free(makefile->ASN1Modules[i].module_name);
  }
  Free(makefile->ASN1Modules);
393
394
395
396
397
398
  for (i = 0; i < makefile->nXSDModules; i++) {
    Free(makefile->XSDModules[i].dir_name);
    Free(makefile->XSDModules[i].file_name);
    Free(makefile->XSDModules[i].module_name);
  }
  Free(makefile->XSDModules);
Elemer Lelik's avatar
Elemer Lelik committed
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
  for (i = 0; i < makefile->nUserFiles; i++) {
    Free(makefile->UserFiles[i].dir_name);
    Free(makefile->UserFiles[i].file_prefix);
    Free(makefile->UserFiles[i].header_name);
    Free(makefile->UserFiles[i].source_name);
  }
  Free(makefile->UserFiles);
  for (i = 0; i < makefile->nOtherFiles; i++) Free(makefile->OtherFiles[i]);
  Free(makefile->OtherFiles);
  Free(makefile->BaseDirs);
  Free(makefile->working_dir);
  Free(makefile->ets_name);
  Free(makefile->output_file);
  Free(makefile->code_splitting_mode);
  Free(makefile->tcov_file_name);
}

/** Displays the contents of structure \a makefile as debug messages. */
static void dump_makefile_struct(const struct makefile_struct *makefile,
  unsigned level)
{
  size_t i;
  DEBUG(level, "Data used for Makefile generation:");
Elemer Lelik's avatar
Elemer Lelik committed
422
  DEBUG(level + 1, "TTCN-3 project name: %s", makefile->project_name);
Elemer Lelik's avatar
Elemer Lelik committed
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
  DEBUG(level + 1, "TTCN-3 modules: (%u pcs.)", makefile->nTTCN3Modules);
  for (i = 0; i < makefile->nTTCN3Modules; i++) {
    const struct module_struct *module = makefile->TTCN3Modules + i;
    DEBUG(level + 2, "Module name: %s", module->module_name);
    if (module->dir_name != NULL)
      DEBUG(level + 3, "Directory: %s", module->dir_name);
    DEBUG(level + 3, "File name: %s", module->file_name);
    DEBUG(level + 3, "Follows the naming convention: %s",
      module->is_regular ? "yes" : "no");
  }
  DEBUG(level + 1, "TTCN-3 preprocessing: %s",
        makefile->preprocess ? "yes" : "no");
  if (makefile->preprocess) {
    DEBUG(level + 1, "TTCN-3 modules to be preprocessed: (%u pcs.)",
          makefile->nTTCN3PPModules);
    for (i = 0; i < makefile->nTTCN3PPModules; i++) {
      const struct module_struct *module = makefile->TTCN3PPModules + i;
      DEBUG(level + 2, "Module name: %s", module->module_name);
      if (module->dir_name != NULL)
        DEBUG(level + 3, "Directory: %s", module->dir_name);
      DEBUG(level + 3, "File name: %s", module->file_name);
      DEBUG(level + 3, "Follows the naming convention: %s",
        module->is_regular ? "yes" : "no");
    }
    DEBUG(level + 1, "TTCN-3 include files: (%u pcs.)",
      makefile->nTTCN3IncludeFiles);
    for (i = 0; i < makefile->nTTCN3IncludeFiles; i++)
      DEBUG(level + 2, "File name: %s", makefile->TTCN3IncludeFiles[i]);
  }
  DEBUG(level + 1, "All local TTCN-3 modules follow the naming convention: %s",
    makefile->TTCN3ModulesRegular ? "yes" : "no");
  if (makefile->central_storage) DEBUG(level + 1, "All TTCN-3 modules from other "
    "directories follow the naming convention: %s",
    makefile->BaseTTCN3ModulesRegular ? "yes" : "no");
  DEBUG(level + 1, "ASN.1 modules: (%u pcs.)", makefile->nASN1Modules);
  for (i = 0; i < makefile->nASN1Modules; i++) {
    const struct module_struct *module = makefile->ASN1Modules + i;
    DEBUG(level + 2, "Module name: %s", module->module_name);
    if (module->dir_name != NULL)
      DEBUG(level + 3, "Directory: %s", module->dir_name);
    DEBUG(level + 3, "File name: %s", module->file_name);
    DEBUG(level + 3, "Follows the naming convention: %s",
      module->is_regular ? "yes" : "no");
  }
  DEBUG(level + 1, "All local ASN.1 modules follow the naming convention: %s",
    makefile->ASN1ModulesRegular ? "yes" : "no");
  if (makefile->central_storage) DEBUG(level + 1, "All ASN.1 modules from other "
    "directories follow the naming convention: %s",
    makefile->BaseASN1ModulesRegular ? "yes" : "no");
  DEBUG(level + 1, "User C/C++ modules: (%u pcs.)", makefile->nUserFiles);
  for (i = 0; i < makefile->nUserFiles; i++) {
    const struct user_struct *user = makefile->UserFiles + i;
    DEBUG(level + 2, "File prefix: %s", user->file_prefix);
    if (user->dir_name != NULL)
      DEBUG(level + 3, "Directory: %s", user->dir_name);
    if (user->header_name != NULL) {
      DEBUG(level + 3, "Header file: %s", user->header_name);
      DEBUG(level + 3, "Header file has .hh or .hpp suffix: %s",
Elemer Lelik's avatar
Elemer Lelik committed
481
      user->has_hh_suffix ? "yes" : "no");
Elemer Lelik's avatar
Elemer Lelik committed
482
483
484
485
    }
    if (user->source_name != NULL) {
      DEBUG(level + 3, "Source file: %s", user->source_name);
      DEBUG(level + 3, "Source file has .cc or .cpp suffix: %s",
Elemer Lelik's avatar
Elemer Lelik committed
486
      user->has_cc_suffix ? "yes" : "no");
Elemer Lelik's avatar
Elemer Lelik committed
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
      DEBUG(level + 3, "Object file: %s.o", user->file_prefix);
    }
  }
  DEBUG(level + 1, "All local C/C++ header files follow the naming "
    "convention: %s", makefile->UserHeadersRegular ? "yes" : "no");
  DEBUG(level + 1, "All local C/C++ source files follow the naming "
    "convention: %s", makefile->UserSourcesRegular ? "yes" : "no");
  if (makefile->central_storage) {
    DEBUG(level + 1, "All C/C++ header files from other directories follow the "
      "naming convention: %s", makefile->BaseUserHeadersRegular ? "yes" : "no");
    DEBUG(level + 1, "All C/C++ source files from other directories follow the "
      "naming convention: %s", makefile->BaseUserSourcesRegular ? "yes" : "no");
  }
  DEBUG(level + 1, "Other files: (%u pcs.)", makefile->nOtherFiles);
  for (i = 0; i < makefile->nOtherFiles; i++)
    DEBUG(level + 2, "File name: %s", makefile->OtherFiles[i]);
  DEBUG(level + 1, "Use pre-compiled files from central storage: %s",
    makefile->central_storage ? "yes" : "no");
  if (makefile->central_storage) {
    DEBUG(level + 1, "Directories of pre-compiled files: (%u pcs.)",
      makefile->nBaseDirs);
    for (i = 0; i < makefile->nBaseDirs; i++) {
      const struct base_dir_struct *base_dir = makefile->BaseDirs + i;
      DEBUG(level + 2, "Directory: %s", base_dir->dir_name);
      DEBUG(level + 3, "Has TTCN-3/ASN.1 modules: %s",
Elemer Lelik's avatar
Elemer Lelik committed
512
      base_dir->has_modules ? "yes" : "no");
Elemer Lelik's avatar
Elemer Lelik committed
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
    }
  }
  DEBUG(level + 1, "Working directory: %s",
    makefile->working_dir != NULL ? makefile->working_dir : "<unknown>");
  DEBUG(level + 1, "GNU make: %s", makefile->gnu_make ? "yes" : "no");
  DEBUG(level + 1, "Execution mode: %s",
    makefile->single_mode ? "single" : "parallel");
  DEBUG(level + 1, "Name of executable: %s",
    makefile->ets_name != NULL ? makefile->ets_name : "<unknown>");
  DEBUG(level + 1, "Output file: %s",
    makefile->output_file != NULL ? makefile->output_file : "<unknown>");
  DEBUG(level + 1, "Force overwrite: %s",
    makefile->force_overwrite ? "yes" : "no");
  DEBUG(level + 1, "Use function test runtime: %s",
    makefile->use_runtime_2 ? "yes" : "no");
  DEBUG(level + 1, "Use dynamic linking: %s",
    makefile->dynamic ? "yes" : "no");
  DEBUG(level + 1, "Code splitting mode: %s",
    makefile->code_splitting_mode != NULL ?
      makefile->code_splitting_mode : "<unknown>");
  DEBUG(level + 1, "Code coverage file: %s",
    makefile->tcov_file_name != NULL ?
      makefile->tcov_file_name : "<unknown>");
Elemer Lelik's avatar
Elemer Lelik committed
536
537
538
539
540
541
542
543
544
545
  if (makefile->profiled_file_list) {
    char* lists = mcopystr(makefile->profiled_file_list->str);
    struct string_list* iter = makefile->profiled_file_list->next;
    while(iter != NULL) {
      lists = mputprintf(lists, " %s", iter->str);
      iter = iter->next;
    }
    DEBUG(level + 1, "Profiled file list(s): %s", lists);
    Free(lists);
  }
Elemer Lelik's avatar
Elemer Lelik committed
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
#ifdef COVERAGE_BUILD
  DEBUG(level + 1, "Enable coverage: %s", makefile->coverage ? "yes" : "no");
#endif
}

/** Returns the name of an existing file that is related to command line
 * argument \a argument. Tries the given list of suffixes. NULL pointer is
 * returned if no file was found. The returned string shall be deallocated
 * by the caller. */
static char *get_file_name_for_argument(const char *argument)
{
  static const char * const suffix_list[] = {
    "", ".ttcnpp", ".ttcnin", ".ttcn", ".ttcn3", ".3mp", ".asn", ".asn1",
    ".cc", ".c", ".cpp", ".hh", ".h",".hpp", ".cfg", ".prj", NULL
  };
  const char * const *suffix_ptr;
  for (suffix_ptr = suffix_list; *suffix_ptr != NULL; suffix_ptr++) {
    char *file_name = mputstr(mcopystr(argument), *suffix_ptr);
    if (get_path_status(file_name) == PS_FILE) return file_name;
    Free(file_name);
  }
  return NULL;
}

/** Converts \a path_name to an absolute directory using \a working_dir.
 * NULL pointer is returned if \a path_name does not contain a directory or
 * the resulting absolute directory is identical to \a working_dir.
 * The returned string shall be deallocated by the caller. */
static char *get_dir_name(const char *path_name, const char *working_dir)
{
  char *dir_name = get_dir_from_path(path_name);
  if (dir_name != NULL) {
Elemer Lelik's avatar
Elemer Lelik committed
578
    char *absolute_dir = get_absolute_dir(dir_name, working_dir, TRUE);
Elemer Lelik's avatar
Elemer Lelik committed
579
580
581
    Free(dir_name);
    if (absolute_dir == NULL || working_dir == NULL) {
      /* an error occurred */
582
      Free(absolute_dir);
Elemer Lelik's avatar
Elemer Lelik committed
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
      return NULL;
    } else if (!strcmp(absolute_dir, working_dir)) {
      /* the directory is identical to the working dir */
      Free(absolute_dir);
      return NULL;
    } else return absolute_dir;
  } else return NULL;
}

/** Returns whether \a dirname1 and \a dirname2 contain the same (canonized
 * absolute) directories. NULL pointer is handled in a special way: it is
 * identical only to itself. */
static boolean is_same_directory(const char *dirname1, const char *dirname2)
{
  if (dirname1 == NULL) {
    if (dirname2 == NULL) return TRUE;
    else return FALSE;
  } else {
    if (dirname2 == NULL) return FALSE;
    else if (strcmp(dirname1, dirname2)) return FALSE;
    else return TRUE;
  }
}

/** Returns whether the file \a filename1 in directory \a dirname1 is identical
 * to file \a filename2 in directory \a dirname2. Only the directory names can
 * be NULL. */
static boolean is_same_file(const char *dirname1, const char *filename1,
  const char *dirname2, const char *filename2)
{
  /* first examine the file names for efficiency reasons */
  if (strcmp(filename1, filename2)) return FALSE;
  else return is_same_directory(dirname1, dirname2);
}

/** Determines whether the TTCN-3 or ASN.1 module identifiers \a module1 and
 * \a module2 are the same. Characters '-' and '_' in module names are not
 * distinguished. */
static boolean is_same_module(const char *module1, const char *module2)
{
  size_t i;
  for (i = 0; ; i++) {
    switch (module1[i]) {
    case '\0':
      if (module2[i] == '\0') return TRUE;
      else return FALSE;
    case '-':
    case '_':
      if (module2[i] != '-' && module2[i] != '_') return FALSE;
      break;
    default:
      if (module1[i] != module2[i]) return FALSE;
      break;
    }
  }
  return FALSE; /* to avoid warnings */
}

/** Truncates the suffix (i.e. the last dot and the characters following it)
 * from \a file_name and returns a copy of the prefix of \a file_name.
 * If \a file_name does not have a suffix an exact copy of it is returned.
 * The returned string shall be deallocated by the caller. */
static char *cut_suffix(const char *file_name)
{
  char *ret_val;
  size_t last_dot = (size_t)-1;
  size_t i;
  for (i = 0; file_name[i] != '\0'; i++)
    if (file_name[i] == '.') last_dot = i;
  ret_val = mcopystr(file_name);
  if (last_dot != (size_t)-1) ret_val = mtruncstr(ret_val, last_dot);
  return ret_val;
}

/** Determines the name of the preprocessed file from \a file_name.
 *  It is assumed that \a file_name has ttcnpp suffix.
 *  The returned string shall be deallocated by the caller. */
static char *get_preprocessed_file_name(const char *file_name)
{
  char *ret_val = cut_suffix(file_name);
  ret_val = mputstr(ret_val, ".ttcn");
  return ret_val;
}

/** Check if any of the preprocessed ttcn file names with the preprocessed
 * (TTCN-3) suffix is equal to any other file given in the \a makefile */
static void check_preprocessed_filename_collision(
  struct makefile_struct *makefile)
{
  size_t i;
  if (makefile->nTTCN3PPModules == 0) {
    WARNING("TTCN-3 preprocessing (option `-p') is enabled, but no TTCN-3 "
      "files to be preprocessed were given for the Makefile.");
  }
  for (i = 0; i < makefile->nTTCN3PPModules; i++) {
    const struct module_struct *pp_module = makefile->TTCN3PPModules + i;
    /* name of the intermediate preprocessed file */
    char *preprocessed_name = get_preprocessed_file_name(pp_module->file_name);
    size_t j;
    for (j = 0; j < makefile->nTTCN3Modules; j++) {
      struct module_struct *module = makefile->TTCN3Modules + j;
      if (is_same_file(pp_module->dir_name, preprocessed_name,
	module->dir_name, module->file_name)) {
	if (is_same_module(pp_module->module_name, module->module_name)) {
          /* same file with the same module */
	  char *pp_pathname = compose_path_name(pp_module->dir_name,
	    pp_module->file_name);
	  char *m_pathname = compose_path_name(module->dir_name,
	    module->file_name);
	  WARNING("File `%s' containing TTCN-3 module `%s' is generated by "
	    "the preprocessor from `%s'. Removing the file from the list of "
	    "normal TTCN-3 modules.", m_pathname, module->module_name,
	    pp_pathname);
	  Free(pp_pathname);
	  Free(m_pathname);
	  Free(module->dir_name);
	  Free(module->file_name);
	  Free(module->module_name);
	  makefile->nTTCN3Modules--;
	  memmove(module, module + 1, (makefile->nTTCN3Modules - j) *
	    sizeof(*makefile->TTCN3Modules));
	  makefile->TTCN3Modules =
	    (struct module_struct*)Realloc(makefile->TTCN3Modules,
	    makefile->nTTCN3Modules * sizeof(*makefile->TTCN3Modules));
	} else {
          /* same file with different module */
	  char *pp_pathname = compose_path_name(pp_module->dir_name,
	    pp_module->file_name);
	  char *m_pathname = compose_path_name(module->dir_name,
	    module->file_name);
	  ERROR("Preprocessed intermediate file of `%s' (module `%s') clashes "
	    "with file `%s' containing TTCN-3 module `%s'.", pp_pathname,
	    pp_module->module_name, m_pathname, module->module_name);
	  Free(pp_pathname);
	  Free(m_pathname);
	}
      } else if (is_same_module(pp_module->module_name, module->module_name)) {
        /* different file with the same module */
	char *pp_pathname = compose_path_name(pp_module->dir_name,
	  pp_module->file_name);
	char *m_pathname = compose_path_name(module->dir_name,
	  module->file_name);
	ERROR("Both files `%s' and `%s' contain TTCN-3 module `%s'.",
	  pp_pathname, m_pathname, pp_module->module_name);
	Free(pp_pathname);
	Free(m_pathname);
      }
    }
    for (j = 0; j < makefile->nASN1Modules; j++) {
      struct module_struct *module = makefile->ASN1Modules + j;
      if (is_same_file(pp_module->dir_name, preprocessed_name,
	module->dir_name, module->file_name)) {
	char *pp_pathname = compose_path_name(pp_module->dir_name,
	  pp_module->file_name);
	char *m_pathname = compose_path_name(module->dir_name,
	  module->file_name);
	ERROR("Preprocessed intermediate file of `%s' (module `%s') clashes "
	  "with file `%s' containing ASN.1 module `%s'.", pp_pathname,
	  pp_module->module_name, m_pathname, module->module_name);
	Free(pp_pathname);
	Free(m_pathname);
      }
    }
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
    for (j = 0; j < makefile->nXSDModules; j++) {
      struct module_struct *module = makefile->XSDModules + j;
      if (module->dir_name == NULL || module->file_name == NULL) {
        continue;
      }
      if (is_same_file(pp_module->dir_name, preprocessed_name,
	module->dir_name, module->file_name)) {
	char *pp_pathname = compose_path_name(pp_module->dir_name,
	  pp_module->file_name);
	char *m_pathname = compose_path_name(module->dir_name,
	  module->file_name);
	ERROR("Preprocessed intermediate file of `%s' (module `%s') clashes "
	  "with file `%s' containing TTCN-3 module `%s'.", pp_pathname,
	  pp_module->module_name, m_pathname, module->module_name);
	Free(pp_pathname);
	Free(m_pathname);
      }
    }
Elemer Lelik's avatar
Elemer Lelik committed
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
    for (j = 0; j < makefile->nOtherFiles; j++) {
      char *dir_name = get_dir_name(makefile->OtherFiles[j],
                                    makefile->working_dir);
      char *file_name = get_file_from_path(makefile->OtherFiles[j]);
      if (is_same_file(pp_module->dir_name, preprocessed_name, dir_name,
	file_name)) {
	char *pp_pathname = compose_path_name(pp_module->dir_name,
	  pp_module->file_name);
	ERROR("Preprocessed intermediate file of `%s' (module `%s') clashes "
	  "with other file `%s'.", pp_pathname, pp_module->module_name,
	  makefile->OtherFiles[j]);
	Free(pp_pathname);
      }
      Free(dir_name);
      Free(file_name);
    }
    Free(preprocessed_name);
  }
}

/** Checks the name clash between existing module \a module and newly added
 * module with parameters \a path_name, \a dir_name, \a file_name,
 * \a module_name. Both the existing and the new module shall be of the same
 * kind, parameter \a kind shall contain the respective string (either "ASN.1"
 * or "TTCN-3"). If a clash is found the parameters of the new module except
 * \a path_name are deallocated and TRUE is returned. Otherwise FALSE is
 * returned. */
static boolean check_module_clash_same(const struct module_struct *module,
  const char *kind, const char *path_name, char *dir_name, char *file_name,
  char *module_name)
{
  if (is_same_module(module_name, module->module_name)) {
    if (is_same_file(dir_name, file_name,
        module->dir_name, module->file_name)) {
      /* the same file was given twice: just issue a warning */
      WARNING("File `%s' was given more than once for the Makefile.",
              path_name);
    } else {
      /* two different files contain the same module: this cannot be
       * resolved as the generated C++ files will clash */
      char *path_name1 = compose_path_name(module->dir_name,
	module->file_name);
      char *path_name2 = compose_path_name(dir_name, file_name);
      ERROR("Both files `%s' and `%s' contain %s module `%s'.",
	path_name1, path_name2, kind, module_name);
      Free(path_name1);
      Free(path_name2);
    }
    Free(file_name);
    Free(dir_name);
    Free(module_name);
    return TRUE;
  } else return FALSE;
}

/** Checks the name clash between existing module \a module and newly added
 * module with parameters \a dir_name, \a file_name, \a module_name. The two
 * modules shall be of different kinds (one is ASN.1, the other is TTCN-3).
 * Parameters \a kind1 and \a kind2 shall contain the respective strings. If a
 * clash is found the parameters of the new module are deallocated and TRUE is
 * returned. Otherwise FALSE is returned. */
static boolean check_module_clash_different(const struct module_struct *module,
  const char *kind1, char *dir_name, char *file_name, char *module_name,
  const char *kind2)
{
  if (is_same_module(module_name, module->module_name)) {
    /* two different files contain the same module: this cannot be resolved
     * as the generated C++ files will clash */
    char *path_name1 = compose_path_name(module->dir_name, module->file_name);
    char *path_name2 = compose_path_name(dir_name, file_name);
    ERROR("File `%s' containing %s module `%s' and file `%s' containing "
      "%s module `%s' cannot be used together in the same Makefile.",
      path_name1, kind1, module->module_name, path_name2, kind2, module_name);
    Free(path_name1);
    Free(path_name2);
    Free(file_name);
    Free(dir_name);
    Free(module_name);
    return TRUE;
  } else return FALSE;
}

/** Adds a TTCN-3 module to Makefile descriptor structure \a makefile.
 * The name of the TTCN-3 source file is \a path_name, the module identifier
 * is \a module_name. It is checked whether a file or module with the same name
 * already exists in \a makefile and an appropriate warning or error is
 * reported. */
static void add_ttcn3_module(struct makefile_struct *makefile,
  const char *path_name, char *module_name)
{
  struct module_struct *module;
  char *dir_name = get_dir_name(path_name, makefile->working_dir);
  char *file_name = get_file_from_path(path_name);
  const char *suffix = get_suffix(file_name);
  size_t i;
  boolean is_preprocessed = FALSE;

  if (suffix != NULL) {
    if (!strcmp(suffix, "ttcnpp")) {
      if (makefile->preprocess) is_preprocessed = TRUE;
      else WARNING("The suffix of TTCN-3 file `%s' indicates that it should be "
        "preprocessed, but TTCN-3 preprocessing is not enabled. The file "
        "will be added to the list of normal TTCN-3 modules in the Makefile.",
        path_name);
    } else if (!strcmp(suffix, "ttcnin")) {
      WARNING("The suffix of file `%s' indicates that it should be a "
        "preprocessor include file, but it contains a TTCN-3 module named `%s'. "
        "The file will be added to the list of normal TTCN-3 modules in the "
        "Makefile.", path_name, module_name);
    }
  }

  for (i = 0; i < makefile->nASN1Modules; i++) {
    if (check_module_clash_different(makefile->ASN1Modules + i, "ASN.1",
      dir_name, file_name, module_name, "TTCN-3")) return;
  }
  /* never entered if suffix is NULL */
  if (is_preprocessed) {
    char *file_prefix;
    for (i = 0; i < makefile->nTTCN3PPModules; i++) {
      if (check_module_clash_same(makefile->TTCN3PPModules + i, "TTCN-3",
          path_name, dir_name, file_name, module_name)) return;
    }
887
888
889
890
    for (i = 0; i < makefile->nXSDModules; i++) {
      if (check_module_clash_different(makefile->XSDModules + i, "TTCN-3",
        dir_name, file_name, module_name, "TTCN-3")) return;
    }
Elemer Lelik's avatar
Elemer Lelik committed
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
    /* clashes with normal TTCN-3 modules will be checked (and maybe resolved)
     * in \a check_preprocessed_filename_collision() */
    /* add it to the list of TTCN-3 modules to be preprocessed */
    makefile->TTCN3PPModules = (struct module_struct*)
      Realloc(makefile->TTCN3PPModules,
        (makefile->nTTCN3PPModules + 1) * sizeof(*makefile->TTCN3PPModules));
    module = makefile->TTCN3PPModules + makefile->nTTCN3PPModules;
    makefile->nTTCN3PPModules++;
    module->dir_name = dir_name;
    module->file_name = file_name;
    module->module_name = module_name;
    file_prefix = cut_suffix(file_name);
    if (!strcmp(file_prefix, module_name)) module->is_regular = TRUE;
    else module->is_regular = FALSE;
    Free(file_prefix);
  } else {
    /* the file is not preprocessed */
    for (i = 0; i < makefile->nTTCN3Modules; i++) {
      if (check_module_clash_same(makefile->TTCN3Modules + i, "TTCN-3",
          path_name, dir_name, file_name, module_name)) return;
    }
    /* clashes with preprocessed TTCN-3 modules will be checked (and maybe
     * resolved) in \a check_preprocessed_filename_collision() */
    /* add it to the list of normal TTCN-3 modules */
    makefile->TTCN3Modules = (struct module_struct*)
      Realloc(makefile->TTCN3Modules,
        (makefile->nTTCN3Modules + 1) * sizeof(*makefile->TTCN3Modules));
    module = makefile->TTCN3Modules + makefile->nTTCN3Modules;
    makefile->nTTCN3Modules++;
    module->dir_name = dir_name;
    module->file_name = file_name;
    module->module_name = module_name;
    if (suffix != NULL && !strcmp(suffix, "ttcn")) {
      char *file_prefix = cut_suffix(file_name);
      if (!strcmp(file_prefix, module_name)) module->is_regular = TRUE;
      else module->is_regular = FALSE;
      Free(file_prefix);
    } else {
      module->is_regular = FALSE;
    }
  }
}

/** ASN.1 filename shall contain no hyphen */
static boolean is_valid_asn1_filename(const char* file_name)
{
  if (0 == strchr(file_name, '-')) {
    return TRUE;
  }
  return FALSE;
}

/** Adds an ASN.1 module to Makefile descriptor structure \a makefile.
 * The name of the ASN.1 source file is \a path_name, the module identifier
 * is \a module_name. It is checked whether a file or module with the same name
 * already exists in \a makefile and an appropriate warning or error is
 * reported. */
static void add_asn1_module(struct makefile_struct *makefile,
  const char *path_name, char *module_name)
{
  struct module_struct *module;
  char *dir_name = get_dir_name(path_name, makefile->working_dir);
  char *file_name = get_file_from_path(path_name);
  const char *suffix = get_suffix(file_name);
  size_t i;
  for (i = 0; i < makefile->nASN1Modules; i++) {
    if (check_module_clash_same(makefile->ASN1Modules + i, "ASN.1", path_name,
      dir_name, file_name, module_name)) return;
  }
  for (i = 0; i < makefile->nTTCN3Modules; i++) {
    if (check_module_clash_different(makefile->TTCN3Modules + i, "TTCN-3",
      dir_name, file_name, module_name, "ASN.1")) return;
  }
  if (makefile->preprocess) {
    for (i = 0; i < makefile->nTTCN3PPModules; i++) {
      if (check_module_clash_different(makefile->TTCN3PPModules + i, "TTCN-3",
	dir_name, file_name, module_name, "ASN.1")) return;
    }
  }
970
971
972
973
  for (i = 0; i < makefile->nXSDModules; i++) {
    if (check_module_clash_different(makefile->XSDModules + i, "TTCN-3",
      dir_name, file_name, module_name, "ASN.1")) return;
  }
Elemer Lelik's avatar
Elemer Lelik committed
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
  makefile->ASN1Modules = (struct module_struct*)
    Realloc(makefile->ASN1Modules,
      (makefile->nASN1Modules + 1) * sizeof(*makefile->ASN1Modules));
  module = makefile->ASN1Modules + makefile->nASN1Modules;
  makefile->nASN1Modules++;
  module->dir_name = dir_name;
  module->file_name = file_name;
  module->module_name = module_name;
  if (suffix != NULL && !strcmp(suffix, "asn")) {
    char *file_prefix = cut_suffix(file_name);
    /* replace all '_' with '-' in file name prefix */
    for (i = 0; file_prefix[i] != '\0'; i++)
      if (file_prefix[i] == '_') file_prefix[i] = '-';
    if (!strcmp(file_prefix, module_name)) module->is_regular = TRUE;
    else module->is_regular = FALSE;
    Free(file_prefix);
  } else {
    module->is_regular = FALSE;
  }
}

995
996
997
998
999
1000
/** Adds an XSD module to Makefile descriptor structure \a makefile.
 * The name of the XSD source file is \a path_name, the module identifier
 * is \a module_name. It is checked whether a file or module with the same name
 * already exists in \a makefile and an appropriate warning or error is
 * reported. */
static void add_xsd_module(struct makefile_struct *makefile,
For faster browsing, not all history is shown. View entire blame