summaryrefslogtreecommitdiff
path: root/c_check
blob: 314c2b157cac1000ec54c9c319d45fd5643ce74b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
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
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
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
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
#!/usr/bin/perl

#use File::Basename;
# use File::Temp qw(tempfile);

# Checking cross compile
$hostos   = `uname -s | sed -e s/\-.*//`;    chop($hostos);
$hostarch = `uname -m | sed -e s/i.86/x86/`;chop($hostarch);
$hostarch = `uname -p` if ($hostos eq "AIX");
$hostarch = "x86_64" if ($hostarch eq "amd64");
$hostarch = "arm" if ($hostarch =~ /^arm.*/);
$hostarch = "arm64" if ($hostarch eq "aarch64");
$hostarch = "power" if ($hostarch =~ /^(powerpc|ppc).*/);
$hostarch = "zarch" if ($hostarch eq "s390x");

#$tmpf = new File::Temp( UNLINK => 1 );
$binary = $ENV{"BINARY"};

$makefile = shift(@ARGV);
$config   = shift(@ARGV);

$compiler_name = shift(@ARGV);
$flags = join(" ", @ARGV);

# First, we need to know the target OS and compiler name

$data = `$compiler_name $flags -E ctest.c`;

if ($?) {
    printf STDERR "C Compiler ($compiler_name) is something wrong.\n";
    die 1;
}

$cross_suffix = "";

eval "use File::Basename";
if ($@){ 
    warn "could not load PERL module File::Basename, emulating its functionality";
    my $dirnam = substr($compiler_name, 0, rindex($compiler_name, "/")-1 );
    if ($dirnam ne ".") {
	$cross_suffix .= $dirnam . "/";
    }
    my $basnam = substr($compiler_name, rindex($compiler_name,"/")+1, length($compiler_name)-rindex($compiler_name,"/")-1);
	if ($basnam =~ /([^\s]*-)(.*)/) {
	$cross_suffix .= $1;
    }
} else {
    if (dirname($compiler_name) ne ".") {
	$cross_suffix .= dirname($compiler_name) . "/";
    }

    if (basename($compiler_name) =~ /([^\s]*-)(.*)/) {
	$cross_suffix .= $1;
    }
}

$compiler = "";
$compiler = LSB       if ($data =~ /COMPILER_LSB/);
$compiler = CLANG     if ($data =~ /COMPILER_CLANG/);
$compiler = PGI       if ($data =~ /COMPILER_PGI/);
$compiler = PATHSCALE if ($data =~ /COMPILER_PATHSCALE/);
$compiler = INTEL     if ($data =~ /COMPILER_INTEL/);
$compiler = OPEN64    if ($data =~ /COMPILER_OPEN64/);
$compiler = SUN       if ($data =~ /COMPILER_SUN/);
$compiler = IBM       if ($data =~ /COMPILER_IBM/);
$compiler = DEC       if ($data =~ /COMPILER_DEC/);
$compiler = GCC       if ($compiler eq "");

$os = Linux           if ($data =~ /OS_LINUX/);
$os = FreeBSD         if ($data =~ /OS_FREEBSD/);
$os = NetBSD          if ($data =~ /OS_NETBSD/);
$os = OpenBSD         if ($data =~ /OS_OPENBSD/);
$os = DragonFly       if ($data =~ /OS_DRAGONFLY/);
$os = Darwin          if ($data =~ /OS_DARWIN/);
$os = SunOS           if ($data =~ /OS_SUNOS/);
$os = AIX             if ($data =~ /OS_AIX/);
$os = osf             if ($data =~ /OS_OSF/);
$os = WINNT           if ($data =~ /OS_WINNT/);
$os = CYGWIN_NT       if ($data =~ /OS_CYGWIN_NT/);
$os = Interix         if ($data =~ /OS_INTERIX/);
$os = Android         if ($data =~ /OS_ANDROID/);
$os = Haiku           if ($data =~ /OS_HAIKU/);

$architecture = x86    if ($data =~ /ARCH_X86/);
$architecture = x86_64 if ($data =~ /ARCH_X86_64/);
$architecture = power  if ($data =~ /ARCH_POWER/);
$architecture = mips   if ($data =~ /ARCH_MIPS/);
$architecture = mips64 if ($data =~ /ARCH_MIPS64/);
$architecture = alpha  if ($data =~ /ARCH_ALPHA/);
$architecture = sparc  if ($data =~ /ARCH_SPARC/);
$architecture = ia64   if ($data =~ /ARCH_IA64/);
$architecture = arm    if ($data =~ /ARCH_ARM/);
$architecture = arm64  if ($data =~ /ARCH_ARM64/);
$architecture = zarch  if ($data =~ /ARCH_ZARCH/);

$defined = 0;

if ($os eq "AIX") {
    $compiler_name .= " -maix32" if ($binary eq "32");
    $compiler_name .= " -maix64" if ($binary eq "64");
    $defined = 1;
}

if ($architecture eq "mips") {
    $compiler_name .= " -mabi=32";
    $defined = 1;
}

if ($architecture eq "mips64") {
    $compiler_name .= " -mabi=n32" if ($binary eq "32");
    $compiler_name .= " -mabi=64" if ($binary eq "64");
    $defined = 1;
}

if (($architecture eq "arm") || ($architecture eq "arm64")) {
    $defined = 1;
}

if ($architecture eq "zarch") {
    $defined = 1;
    $binary = 64;
}

if ($architecture eq "alpha") {
    $defined = 1;
    $binary = 64;
}

if ($architecture eq "ia64") {
    $defined = 1;
    $binary = 64;
}

if (($architecture eq "x86") && ($os ne Darwin) && ($os ne SunOS)) {
    $defined = 1;
    $binary =32;
}

if ($compiler eq "PGI") {
    $compiler_name .= " -tp p7"    if ($binary eq "32");
    $compiler_name .= " -tp p7-64" if ($binary eq "64");
    $openmp = "-mp";
    $defined = 1;
}

if ($compiler eq "IBM") {
    $compiler_name .= " -q32"  if ($binary eq "32");
    $compiler_name .= " -q64"  if ($binary eq "64");
    $openmp = "-qsmp=omp";
    $defined = 1;
}

if ($compiler eq "INTEL") {
    $openmp = "-openmp";
}

if ($compiler eq "PATHSCALE") {
    $openmp = "-mp";
}

if ($compiler eq "OPEN64") {
    $openmp = "-mp";
}

if ($compiler eq "CLANG") {
    $openmp = "-fopenmp";
}

if ($compiler eq "GCC" || $compiler eq "LSB") {
    $openmp = "-fopenmp";
}

if ($defined == 0) {
    $compiler_name .= " -m32" if ($binary eq "32");
    $compiler_name .= " -m64" if ($binary eq "64");
}

# Do again

$data = `$compiler_name $flags -E ctest.c`;

if ($?) {
    printf STDERR "C Compiler ($compiler_name) is something wrong.\n";
    die 1;
}

$have_msa = 0;
if (($architecture eq "mips") || ($architecture eq "mips64")) {
    eval "use File::Temp qw(tempfile)";
    if ($@){ 
	warn "could not load PERL module File::Temp, so could not check MSA capatibility";
    } else {
	$tmpf = new File::Temp( SUFFIX => '.c' , UNLINK => 1 );
	$code = '"addvi.b $w0, $w1, 1"';
	$msa_flags = "-mmsa -mfp64 -msched-weight -mload-store-pairs";
	print $tmpf "#include <msa.h>\n\n";
	print $tmpf "void main(void){ __asm__ volatile($code); }\n";

	$args = "$msa_flags -o $tmpf.o $tmpf";
	my @cmd = ("$compiler_name $flags $args >/dev/null 2>/dev/null");
	system(@cmd) == 0;
	if ($? != 0) {
	    $have_msa = 0;
	} else {
	    $have_msa = 1;
	}
	unlink("$tmpf.o");
    }
}

$architecture = x86    if ($data =~ /ARCH_X86/);
$architecture = x86_64 if ($data =~ /ARCH_X86_64/);
$architecture = power  if ($data =~ /ARCH_POWER/);
$architecture = mips   if ($data =~ /ARCH_MIPS/);
$architecture = mips64 if ($data =~ /ARCH_MIPS64/);
$architecture = alpha  if ($data =~ /ARCH_ALPHA/);
$architecture = sparc  if ($data =~ /ARCH_SPARC/);
$architecture = ia64   if ($data =~ /ARCH_IA64/);
$architecture = arm    if ($data =~ /ARCH_ARM/);
$architecture = arm64  if ($data =~ /ARCH_ARM64/);
$architecture = zarch  if ($data =~ /ARCH_ZARCH/);

$binformat    = bin32;
$binformat    = bin64  if ($data =~ /BINARY_64/);

$no_avx512= 0;
if (($architecture eq "x86") || ($architecture eq "x86_64")) {
    eval "use File::Temp qw(tempfile)";
    if ($@){ 
	warn "could not load PERL module File::Temp, so could not check compiler compatibility with AVX512";
	$no_avx512 = 0;
    } else {
#	$tmpf = new File::Temp( UNLINK => 1 );
	($fh,$tmpf) = tempfile( SUFFIX => '.c' , UNLINK => 1 );
	$code = '"vbroadcastss -4 * 4(%rsi), %zmm2"';
	print $tmpf "#include <immintrin.h>\n\nint main(void){ __asm__ volatile($code); }\n";
	$args = " -march=skylake-avx512 -c -o $tmpf.o $tmpf";
	if ($compiler eq "PGI") {
	    $args = " -tp skylake -c -o $tmpf.o $tmpf";
	}
	my @cmd = ("$compiler_name $flags $args >/dev/null 2>/dev/null");
	system(@cmd) == 0;
	if ($? != 0) {
	    $no_avx512 = 1;
	} else {
	    $no_avx512 = 0;
	}
	unlink("$tmpf.o");
    }
}

$c11_atomics = 0;
if ($data =~ /HAVE_C11/) {
    eval "use File::Temp qw(tempfile)";
    if ($@){ 
       warn "could not load PERL module File::Temp, so could not check compiler compatibility with C11";
       $c11_atomics = 0;
    } else {
       ($fh,$tmpf) = tempfile( SUFFIX => '.c' , UNLINK => 1 );
       print $tmpf "#include <stdatomic.h>\nint main(void){}\n";
       $args = " -c -o $tmpf.o $tmpf";
       my @cmd = ("$compiler_name $flags $args >/dev/null 2>/dev/null");
       system(@cmd) == 0;
       if ($? != 0) {
           $c11_atomics = 0;
       } else {
           $c11_atomics = 1;
       }
       unlink("$tmpf.o");
    }
}


$data = `$compiler_name $flags -S ctest1.c && grep globl ctest1.s | head -n 1 && rm -f ctest1.s`;

$data =~ /globl\s([_\.]*)(.*)/;

$need_fu      = $1;

$cross = 0;

if ($architecture ne $hostarch) {
    $cross = 1;
    $cross = 0 if (($hostarch eq "x86_64") && ($architecture eq "x86"));
    $cross = 0 if (($hostarch eq "mips64") && ($architecture eq "mips"));
}

$cross = 1 if ($os ne $hostos);

$openmp = "" if $ENV{USE_OPENMP} != 1;

$linker_L = "";
$linker_l = "";
$linker_a = "";

{
    $link = `$compiler_name $flags -c ctest2.c -o ctest2.o 2>&1 && $compiler_name $flags $openmp -v ctest2.o -o ctest2 2>&1 && rm -f ctest2.o ctest2 ctest2.exe`;

    $link =~ s/\-Y\sP\,/\-Y/g;

    @flags = split(/[\s\,\n]/, $link);
    # remove leading and trailing quotes from each flag.
    @flags = map {s/^['"]|['"]$//g; $_} @flags;

    foreach $flags (@flags) {
	if (
	    ($flags =~ /^\-L/)
	    && ($flags !~ /^-LIST:/)
	    && ($flags !~ /^-LANG:/)
	    ) {
	    $linker_L .= $flags . " "
	    }

	if ($flags =~ /^\-Y/) {
	    $linker_L .= "-Wl,". $flags . " "
	    }

	if ($flags =~ /^\--exclude-libs/) {
	    $linker_L .= "-Wl,". $flags . " ";
	    $flags="";
	   }

	if (
	    ($flags =~ /^\-l/)
	    && ($flags !~ /gfortranbegin/)
	    && ($flags !~ /frtbegin/)
	    && ($flags !~ /pathfstart/)
	    && ($flags !~ /numa/)
	    && ($flags !~ /crt[0-9]/)
	    && ($flags !~ /gcc/)
	    && ($flags !~ /user32/)
	    && ($flags !~ /kernel32/)
	    && ($flags !~ /advapi32/)
	    && ($flags !~ /shell32/)
	    && ($flags !~ /omp/)
	    && ($flags !~ /[0-9]+/)
	    ) {
	    $linker_l .= $flags . " "
	}

	$linker_a .= $flags . " " if $flags =~ /\.a$/;
    }

}

open(MAKEFILE, "> $makefile") || die "Can't create $makefile";
open(CONFFILE, "> $config"  ) || die "Can't create $config";

# print $data, "\n";

print MAKEFILE "OSNAME=$os\n";
print MAKEFILE "ARCH=$architecture\n";
print MAKEFILE "C_COMPILER=$compiler\n";
print MAKEFILE "BINARY32=\n" if $binformat ne bin32;
print MAKEFILE "BINARY64=\n" if $binformat ne bin64;
print MAKEFILE "BINARY32=1\n" if $binformat eq bin32;
print MAKEFILE "BINARY64=1\n" if $binformat eq bin64;
print MAKEFILE "FU=$need_fu\n" if $need_fu ne "";
print MAKEFILE "CROSS_SUFFIX=$cross_suffix\n" if $cross != 0 && $cross_suffix ne "";
print MAKEFILE "CROSS=1\n" if $cross != 0;
print MAKEFILE "CEXTRALIB=$linker_L $linker_l $linker_a\n";
print MAKEFILE "HAVE_MSA=1\n" if $have_msa eq 1;
print MAKEFILE "MSA_FLAGS=$msa_flags\n" if $have_msa eq 1;
print MAKEFILE "NO_AVX512=1\n" if $no_avx512 eq 1;

$os           =~ tr/[a-z]/[A-Z]/;
$architecture =~ tr/[a-z]/[A-Z]/;
$compiler     =~ tr/[a-z]/[A-Z]/;

print CONFFILE "#define OS_$os\t1\n";
print CONFFILE "#define ARCH_$architecture\t1\n";
print CONFFILE "#define C_$compiler\t1\n";
print CONFFILE "#define __32BIT__\t1\n"  if $binformat eq bin32;
print CONFFILE "#define __64BIT__\t1\n"  if $binformat eq bin64;
print CONFFILE "#define FUNDERSCORE\t$need_fu\n" if $need_fu ne "";
print CONFFILE "#define HAVE_MSA\t1\n"  if $have_msa eq 1;
print CONFFILE "#define HAVE_C11\t1\n" if $c11_atomics eq 1;


if ($os eq "LINUX") {

#    @pthread = split(/\s+/, `nm /lib/libpthread.so* | grep _pthread_create`);

#    if ($pthread[2] ne "") {
#	print CONFFILE "#define PTHREAD_CREATE_FUNC	$pthread[2]\n";
#    } else {
	print CONFFILE "#define PTHREAD_CREATE_FUNC	pthread_create\n";
#    }
} else {
    print CONFFILE "#define PTHREAD_CREATE_FUNC	pthread_create\n";
}

close(MAKEFILE);
close(CONFFILE);