]> mj.ucw.cz Git - libucw.git/blob - ucw/perl/UCW/Configure/C.pm
Configure: Introduce AtWrite hooks and handle autoconf.h by them.
[libucw.git] / ucw / perl / UCW / Configure / C.pm
1 # UCW Library configuration system: OS and C compiler
2 # (c) 2005--2008 Martin Mares <mj@ucw.cz>
3 # (c) 2006 Robert Spalek <robert@ucw.cz>
4 # (c) 2008 Michal Vaner <vorner@ucw.cz>
5
6 ### OS ###
7
8 package UCW::Configure::C;
9 use UCW::Configure;
10
11 Test("OS", "Checking on which OS we run", sub {
12         my $os = `uname`;
13         chomp $os;
14         Fail "Unable to determine OS type" if $? || $os eq "";
15         return $os;
16 });
17
18 if (Get("OS") eq "Linux") {
19         Set("CONFIG_LINUX");
20 } elsif (Get("OS") eq "Darwin") {
21         Set("CONFIG_DARWIN");
22 } else {
23         Fail "Don't know how to run on this operating system.";
24 }
25
26 ### Compiler ###
27
28 # Default compiler
29 Test("CC", "Checking for C compiler", sub { return "gcc"; });
30
31 # GCC version
32 Test("GCCVER", "Checking for GCC version", sub {
33         my $gcc = Get("CC");
34         my $ver = `$gcc --version | sed '2,\$d; s/^\\(.* \\)*\\([0-9]*\\.[0-9]*\\).*/\\2/'`;
35         chomp $ver;
36         Fail "Unable to determine GCC version" if $? || $ver eq "";
37         return $ver;
38 });
39 my ($gccmaj, $gccmin) = split(/\./, Get("GCCVER"));
40 my $gccver = 1000*$gccmaj + $gccmin;
41 $gccver >= 3000 or Fail "GCC older than 3.0 doesn't support C99 well enough.";
42
43 ### CPU ###
44
45 Test("ARCH", "Checking for machine architecture", sub {
46         my $mach = `uname -m`;
47         chomp $mach;
48         Fail "Unable to determine machine type" if $? || $mach eq "";
49         if ($mach =~ /^i[0-9]86$/) {
50                 return "i386";
51         } elsif ($mach =~ /^(x86[_-]|amd)64$/) {
52                 return "amd64";
53         } else {
54                 return "unknown";
55         }
56 });
57
58 sub parse_cpuinfo_linux() {
59         open X, "/proc/cpuinfo" || undef;
60         my %pc = ();
61         while (<X>) {
62                 chomp;
63                 /^$/ && last;
64                 /^([^\t]+)\t+:\s*(.*)$/ and $pc{$1}=$2;
65         }
66         close X;
67         return ($pc{'vendor_id'},
68                 $pc{'cpu family'},
69                 $pc{'model'});
70 }
71
72 sub parse_cpuinfo_darwin() {
73         @cpu = (`sysctl -n machdep.cpu.vendor`,
74                 `sysctl -n machdep.cpu.family`,
75                 `sysctl -n machdep.cpu.model`);
76         chomp @cpu;
77         return @cpu;
78 }
79
80 sub parse_cpuinfo() {
81         my @cpu;
82         if (IsSet("CONFIG_LINUX")) {
83                 @cpu = parse_cpuinfo_linux();
84         } elsif (IsSet("CONFIG_DARWIN")) {
85                 @cpu = parse_cpuinfo_darwin();
86         }
87         $cpu[0] = "" if !defined $cpu[0];
88         $cpu[1] = 0 if !defined $cpu[1];
89         $cpu[2] = 0 if !defined $cpu[2];
90         return @cpu;
91 }
92
93 Test("CPU_ARCH", "Checking for CPU architecture", sub {
94         my $mach = Get("ARCH");
95         my $arch = "";
96         if ($mach eq "i386") {
97                 Set("CPU_I386");
98                 UnSet("CPU_64BIT_POINTERS");
99                 Set("CPU_LITTLE_ENDIAN");
100                 UnSet("CPU_BIG_ENDIAN");
101                 Set("CPU_ALLOW_UNALIGNED");
102                 Set("CPU_STRUCT_ALIGN" => 4);
103                 if (IsSet("CONFIG_EXACT_CPU")) {
104                         my ($vendor, $family, $model) = parse_cpuinfo();
105                         # Try to understand CPU vendor, family and model [inspired by MPlayer's configure script]
106                         if ($vendor eq "AuthenticAMD") {
107                                 if ($family >= 6) {
108                                         if ($model >= 31 && $gccver >= 3004) { $arch = "athlon64"; }
109                                         elsif ($model >= 6 && $gccver >= 3003) { $arch = "athlon-xp"; }
110                                         else { $arch = "athlon"; }
111                                 }
112                         } elsif ($vendor eq "GenuineIntel") {
113                                 if ($family >= 15 && $gccver >= 3003) {
114                                         if ($model >= 4) { $arch = "nocona"; }
115                                         elsif ($model >= 3) { $arch = "prescott"; }
116                                         else { $arch = "pentium4"; }
117                                 } elsif ($family == 6 && $gccver >= 3003) {
118                                         if ($model == 15) { $arch = "prescott"; }
119                                         elsif (($model == 9 || $model == 13) && $gccver >= 3004) { $arch = "pentium-m"; }
120                                         elsif ($model >= 7) { $arch = "pentium3"; }
121                                         elsif ($model >= 3) { $arch = "pentium2"; }
122                                 }
123                         }
124
125                         # No match on vendor, try the family
126                         if ($arch eq "") {
127                                 if ($family >= 6) {
128                                         $arch = "i686";
129                                 } elsif ($family >= 3) {
130                                         $arch = "i${family}86";
131                                 }
132                         }
133                         Log (($arch ne "") ? "(using /proc/cpuinfo) " : "(don't understand /proc/cpuinfo) ");
134                         return $arch;
135                 } else {
136                         return "default";
137                 }
138         } elsif ($mach eq "amd64") {
139                 Set("CPU_AMD64");
140                 Set("CPU_64BIT_POINTERS");
141                 Set("CPU_LITTLE_ENDIAN");
142                 UnSet("CPU_BIG_ENDIAN");
143                 Set("CPU_ALLOW_UNALIGNED");
144                 Set("CPU_STRUCT_ALIGN" => 8);
145                 if (IsSet("CONFIG_EXACT_CPU")) {
146                         # In x86-64 world, the detection is somewhat easier so far...
147                         my ($vendor, $family, $model) = parse_cpuinfo();
148                         if ($vendor eq "AuthenticAMD") {
149                                 $arch = "athlon64";
150                         } elsif ($vendor eq "GenuineIntel") {
151                                 $arch = "nocona";
152                         }
153                         Log (($arch ne "") ? "(using /proc/cpuinfo) " : "(don't understand /proc/cpuinfo) ");
154                         return $arch;
155                 } else {
156                         return "default";
157                 }
158         } else {
159                 return "unknown";
160         }
161 });
162
163 if (Get("CPU_ARCH") eq "unknown") {
164         Warn "CPU architecture not recognized, using defaults, keep fingers crossed.\n";
165 }
166
167 ### Compiler and its Options ###
168
169 # C flags: tell the compiler we're speaking C99, and disable common symbols
170 Set("CLANG" => "-std=gnu99 -fno-common");
171
172 # C optimizations
173 Set("COPT" => '-O2');
174 if (Get("CPU_ARCH") ne "unknown" && Get("CPU_ARCH") ne "default") {
175         Append("COPT", '-march=$(CPU_ARCH)');
176 }
177
178 # C optimizations for highly exposed code
179 Set("COPT2" => '-O3');
180
181 # Warnings
182 Set("CWARNS" => '-Wall -W -Wno-parentheses -Wstrict-prototypes -Wmissing-prototypes -Winline');
183 Set("CWARNS_OFF" => '');
184
185 # Linker flags
186 Set("LOPT" => "");
187
188 # Extra libraries
189 Set("LIBS" => "");
190
191 # Extra flags for compiling and linking shared libraries
192 Set("CSHARED" => '-fPIC');
193 if (IsSet("CONFIG_LOCAL")) {
194         Set("SONAME_PREFIX" => "lib/");
195 } else {
196         Set("SONAME_PREFIX" => "");
197 }
198 if (IsSet("CONFIG_DARWIN")) {
199         Set("LSHARED" => '-dynamiclib -install_name $(SONAME_PREFIX)$(@F)$(SONAME_SUFFIX) -undefined dynamic_lookup');
200 } else {
201         Set("LSHARED" => '-shared -Wl,-soname,$(SONAME_PREFIX)$(@F)$(SONAME_SUFFIX)');
202 }
203
204 # Extra switches depending on GCC version:
205 if ($gccver == 3000) {
206         Append("COPT" => "-fstrict-aliasing");
207 } elsif ($gccver == 3003) {
208         Append("CWARNS" => "-Wundef -Wredundant-decls");
209         Append("COPT" => "-finline-limit=20000 --param max-inline-insns-auto=1000");
210 } elsif ($gccver == 3004) {
211         Append("CWARNS" => "-Wundef -Wredundant-decls");
212         Append("COPT" => "-finline-limit=2000 --param large-function-insns=5000 --param inline-unit-growth=200 --param large-function-growth=400");
213 } elsif ($gccver >= 4000) {
214         Append("CWARNS" => "-Wundef -Wredundant-decls -Wno-pointer-sign -Wdisabled-optimization -Wno-missing-field-initializers");
215         Append("CWARNS_OFF" => "-Wno-pointer-sign");
216         Append("COPT" => "-finline-limit=5000 --param large-function-insns=5000 --param inline-unit-growth=200 --param large-function-growth=400");
217         if ($gccver >= 4002) {
218                 Append("COPT" => "-fgnu89-inline");
219         }
220 } else {
221         Warn "Don't know anything about this GCC version, using default switches.\n";
222 }
223
224 if (IsSet("CONFIG_DEBUG")) {
225         # If debugging:
226         Set("DEBUG_ASSERTS");
227         Set("DEBUG_DIE_BY_ABORT") if Get("CONFIG_DEBUG") > 1;
228         Set("CDEBUG" => "-ggdb");
229 } else {
230         # If building a release version:
231         Append("COPT" => "-fomit-frame-pointer");
232         Append("LOPT" => "-s");
233 }
234
235 if (IsSet("CONFIG_DARWIN")) {
236         # gcc-4.0 on Darwin doesn't set this in the gnu99 mode
237         Append("CLANG" => "-fnested-functions");
238         # Directory hierarchy of the fink project
239         Append("LIBS" => "-L/sw/lib");
240         Append("COPT" => "-I/sw/include");
241         # Fill in some constants not found in the system header files
242         Set("SOL_TCP" => 6);            # missing in /usr/include/netinet/tcp.h
243 }
244
245 ### Writing C headers with configuration ###
246
247 sub ConfigHeader($$) {
248         my ($hdr, $rules) = @_;
249         Log "Generating $hdr ... ";
250         open X, ">obj/$hdr" or Fail $!;
251         print X "/* Generated automatically by $0, please don't touch manually. */\n";
252
253         sub match_rules($) {
254                 my ($name) = @_;
255                 for (my $i=0; $i < scalar @$rules; $i++) {
256                         my ($r, $v) = ($rules->[$i], $rules->[$i+1]);
257                         return $v if $name =~ $r;
258                 }
259                 return 0;
260         }
261
262         foreach my $x (sort keys %UCW::Configure::vars) {
263                 next unless match_rules($x);
264                 my $v = $UCW::Configure::vars{$x};
265                 # Try to add quotes if necessary
266                 $v = '"' . $v . '"' unless ($v =~ /^"/ || $v =~ /^\d*$/);
267                 print X "#define $x $v\n";
268         }
269         close X;
270         Log "done\n";
271 }
272
273 AtWrite {
274         ConfigHeader("autoconf.h", [
275                 # Symbols with "_" anywhere in their name are exported
276                 "_" => 1
277         ]);
278 };
279
280 # Return success
281 1;