file: Add microsecond resolution for mtime: mtimeus
[jimtcl.git] / build-jim-ext.in
blobce9ddf6d96d423edeca18f66af968daf6ee8f29c
1 #!/usr/bin/env jimsh
3 # Separate command line arguments into options and source files
4 set opts {}
5 set sources {}
7 proc usage {{msg {}}} {
8         puts stderr "Usage: build-jim-ext ?--notest? ?--cross? ?--install? ?--static? ?cc-options? ?-o modname? sources..."
9         if {$msg ne ""} {
10                 puts stderr \n$msg
11         }
12         exit 1
15 set linker "@CC@"
16 set testmod 1
17 set cross @cross_compiling@
18 set install 0
19 set static 0
20 set verbose 0
21 set keep 0
22 set includepaths {}
23 set libpaths {}
24 set libs {}
25 for {set i 0} {$i < [llength $argv]} {incr i} {
26         set arg [lindex $argv $i]
27         switch -glob -- $arg {
28                 *.c {
29                         lappend sources $arg
30                 }
31                 *.cpp {
32                         lappend sources $arg
33                         set linker "@CXX@"
34                 }
35                 --notest {
36                         # Don't test to see if the module can be loaded
37                         set testmod 0
38                 }
39                 --cross {
40                         # Don't use standard include/lib paths if cross compiling
41                         set cross 1
42                 }
43                 --install {
44                         # Install to $DESTDIR/@prefix@/lib/jim
45                         set install 1
46                 }
47                 --static {
48                         # Build a static extension that can be linked
49                         set static 1
50                 }
51                 --verbose {
52                         set verbose 1
53                 }
54                 --keep {
55                         # Don't remove intermediate files
56                         set keep 1
57                 }
58                 --help {
59                         usage "Easily builds dynamic (loadable) modules for jim"
60                 }
61                 -o {
62                         incr i
63                         set modname [file rootname [lindex $argv $i]]
64                         if {$modname eq ""} {
65                                 usage "Option -o requires an argument"
66                         }
67                 }
68                 -I* {
69                         lappend includepaths $arg
70                         if {$arg eq "-I"} {
71                                 lappend includepaths [lindex $argv $i]
72                         }
73                 }
74                 -L* {
75                         lappend libpaths $arg
76                         if {$arg eq "-L"} {
77                                 lappend libpaths [lindex $argv $i]
78                         }
79                 }
80                 -l* {
81                         lappend libs $arg
82                 }
83                 -* {
84                         lappend opts $arg
85                 }
86                 default {
87                         usage "Unexpected '$arg'"
88                 }
89         }
92 if {$sources eq ""} {
93         usage "No sources provided"
95 if {![info exists modname]} {
96         set modname [file rootname [file tail [lindex $sources 0]]]
97         # Remove jim- prefix if one exists
98         regsub "^jim-" $modname "" modname
101 if {$static} {
102         set target libjim-$modname.a
103 } else {
104         set target $modname.so
106 puts "Building $target from $sources\n"
108 if {!$cross} {
109         # If not cross compiling, add the standard location after any user include paths
110         lappend includepaths -I@prefix@/include
113 # Work around Tcl's strange behaviour of exec failing if stderr is produced
115 proc exec-catch {verbose cmdlist} {
116         if {$verbose} {
117                 puts [join $cmdlist]
118         }
119         flush stdout
120         set rc [catch {
121                 exec {*}$cmdlist
122         } msg errinfo]
124         # Handle failed case.
125         # Note that Tcl returns rc=1 if there is any stderr,
126         # even if the exit code is 0
127         if {$rc} {
128                 if {[dict get $errinfo -errorcode] ne "NONE"} {
129                         if {!$verbose} {
130                                 puts stderr [join $cmdlist]
131                         }
132                         puts stderr $msg
133                         return 1
134                 }
135         }
136         if {$msg ne ""} {
137                 puts stderr $msg
138         }
139         return 0
142 set CPPFLAGS "-D_GNU_SOURCE"
144 set ljim ""
145 set shobj_cflags ""
146 set shobj_ldflags ""
147 if {!$static} {
148         set shobj_cflags "@SHOBJ_CFLAGS@"
149         if {"@JIM_STATICLIB@" eq "1"} {
150                 puts stderr "Warning: libjim is static. Dynamic module may not work on some platforms.\n"
151                 set shobj_ldflags "@SHOBJ_LDFLAGS@"
152         } else {
153                 # If shared, link against the shared libjim to resolve symbols
154                 set ljim -ljim
155                 set shobj_ldflags "@SHOBJ_LDFLAGS_R@"
156         }
159 set objs {}
160 foreach source $sources {
161         set obj [file rootname [file tail $source]].o
162         if {[string match *.c $source]} {
163                 set compiler "@CC@"
164         } else {
165                 set compiler "@CXX@"
166         }
167         set compile "$compiler @CFLAGS@ $CPPFLAGS $shobj_cflags $includepaths $opts -c -o $obj $source"
168         puts "Compile: $obj"
169         lappend objs $obj
171         set rc [exec-catch $verbose $compile]
172         if {$rc} {
173                 file delete {*}$objs
174                 exit $rc
175         }
178 if {$static} {
179         set ar "@AR@ cq $target $objs"
180         set ranlib "@RANLIB@ $target"
182         puts "Ar:      $target"
183         set rc [exec-catch $verbose $ar]
184         if {rc == 0} {
185                 set rc [exec-catch $verbose $ranlib]
186         }
187         file delete {*}$objs
188         if {$rc} {
189                 file delete $target
190                 exit $rc
191         }
192 } else {
193         if {!$cross} {
194                 # If not cross compiling, add the standard location after any user lib paths
195                 lappend libpaths -L@prefix@/lib
196         }
198         set link "$linker @CFLAGS@ @LDFLAGS@ $shobj_ldflags $libpaths $opts -o $target $objs $ljim @LIBS@ $libs"
200         puts "Link:    $target"
201         set rc [exec-catch $verbose $link]
202         if {!$keep} {
203                 file delete {*}$objs
204         }
205         if {$rc} {
206                 file delete $target
207                 exit $rc
208         }
210         if {$testmod && !$cross} {
211                 # Now, is testing even possible?
212                 # We must be running a compatible jimsh with the load command at least
213                 set testmod 0
214                 set rc [catch {
215                         # This will avoid attempting on Tcl and on jimsh without load
216                         if {[info version] > 0.73 && [exists -command load]} {
217                                 set testmod 1
218                         }
219                 } msg]
220         }
222         set rc [catch {
223                 if {$testmod && !$cross} {
224                         puts "Test:    load $target"
225                         load ./$target
226                 }
227                 if {$install} {
228                         set dest [env DESTDIR ""]@prefix@/lib/jim
229                         puts "Install: $target => $dest"
230                         file mkdir $dest
231                         file copy $target $dest/$target
232                 }
233                 puts "\nSuccess!"
234         } msg]
235         if {$rc} {
236                 puts stderr $msg
237                 exit 1
238         }