CC.tcl is a compiler driver derived from critcl which is intended to convert C.tcl's output into loadable extensions. There is code here for cross-compilation, but that is completely untested. All I can claim is it works on my machine.
# CC - compile C code intertexted in Tcl # # slavishly derived and simplified from the excellent critcl # Colin McCormack, Steve Landers, Jean-Claude Wippler other parties package require platform package provide CC 1.0 # CC - compiler driver namespace eval CC { proc param {name content} { variable param foreach line [split $content \n] { set line [string trim $line] if {![regexp {(\S+)\s+(.*)} $line -> n v]} { dict set param $name $line "" } else { dict set param $name $n $v } } } # platform sets the platform (defaults to platform::generic) # compile compile a C source file to an object file # version print the compiler version number # link link one or more object files and create a shared library # preproc_define preprocess C source file (for critcl::cdefines) # preproc_enum ditto # tclstubs cflag to set USE_TCL_STUBS # tkstubs cflag to set USE_TK_STUBS # debug_memory cflag to enable memory debugging # debug_symbols cflag to add symbols to resulting library # object file extension for object files # output flag to set output file # strip cflag to tell linker to strip symbols # optimize cflag to specify optimization level # include cflag to add an include directory # noassert cflag to turn off assertions in Tcl code # threadflags cflags to enable threaded build # target indicates that this is a cross-compile target # sharedlibext the platform shared library extension # # (Support for Fortran) # fcompile compile a Fortran source file to an object file # fversion print the Fortran compiler version number # flink link one or more object files and create a shared library, # if at least one object file comes from Fortran # foutput Fortran flag to set output file # finclude Fortran flag to add an include directory # fextra_cflags Extra C flags for indicating type of Fortran compiler param * { compile gcc -c -fPIC version gcc -v link gcc -shared -Wl,--export-dynamic -fPIC include -I preproc_define gcc -E -dM preproc_enum gcc -E tclstubs -DUSE_TCL_STUBS tkstubs -DUSE_TK_STUBS debug_memory -DTCL_MEM_DEBUG debug_symbols -ggdb3 object .o output -o %OUTFILE% ldoutput link_debug -ggdb3 link_release link_preload --unresolved-symbols=ignore-in-shared-libs _strip -Wl,-s strip optimize -O2 noassert -DNDEBUG threadflags -DUSE_THREAD_ALLOC=1 -D_REENTRANT=1 -D_THREAD_SAFE=1 -DHAVE_PTHREAD_ATTR_SETSTACKSIZE=1 -DHAVE_READDIR_R=1 -DTCL_THREADS=1 } param linux-* { sharedlibext .so } # default on OSX ppc is universal containing ppc and x86 32 bit param macosx-powerpc { compile gcc -c -arch ppc link gcc -bundle -arch ppc link_preload -undefined dynamic_lookup -mmacosx-version-min=10.3 strip } # default on OSX intel is universal containing x86 32 and 64 bit param macosx-ix86 { compile gcc -c -arch i386 -arch x86_64 link gcc -bundle -arch i386 -arch x86_64 link_preload -undefined dynamic_lookup -mmacosx-version-min=10.3 strip } # target for most common macosx architectures param macosx-most { compile gcc -c -arch i386 -arch x86_64 -arch ppc link gcc -bundle -arch i386 -arch x86_64 -arch ppc link_preload -undefined dynamic_lookup -mmacosx-version-min=10.3 strip } # target for all macosx architectures param macosx-all { compile gcc -c -arch i386 -arch x86_64 -arch ppc -arch ppc64 link gcc -bundle -arch i386 -arch x86_64 -arch ppc -arch ppc64 link_preload -undefined dynamic_lookup -mmacosx-version-min=10.3 strip } # OSX ppc 32 bit param macosx-ppc32 { compile gcc -c -arch ppc link gcc -bundle -arch ppc link_preload -undefined dynamic_lookup strip } # OSX ppc 64 bit param macosx-ppc64 { compile gcc -c -arch ppc64 link gcc -bundle -arch ppc64 link_preload -undefined dynamic_lookup strip } # OSX x86 32 bit param macosx-x86_32 { compile gcc -c -arch i386 link gcc -bundle -arch i386 link_preload -undefined dynamic_lookup strip } # OSX x86 64 bit param macosx-x86_64 { compile gcc -c -arch x86_64 link gcc -bundle -arch x86_64 link_preload -undefined dynamic_lookup strip } # Linux - 32 bit or 64 bit build - select using "-target" if you don't want # the platform default (32 on 32, 64 on 64) param linux-32-* { compile gcc -c -m32 } param linux-64-* { compile gcc -c -m64 } # Windows - using MSVC++ 6.0 # # Note: the language option for cl is -TC for c and -TP for c++ or # it can treat single files -Tc<filename> # param win32-ix86-cl { compile cl -nologo -c link link -nologo preproc_define cl -nologo -E preproc_enum cl -nologo -E object .obj debug_symbols -W3 -Od -Zi -GZ -MDd -D_DEBUG optimize -W3 -O2 -Op -Gs -MD output -Fo%OUTFILE% ldoutput -dll -out:%OUTFILE% link_debug -debug:full -debugtype:cv link_release -release -opt:ref -opt:icf,3 -ws:aggressive link_preload strip version cl } # Cross-compile for Windows using Xmingwin param mingw32 { compile gcc -c -nostdlib link gcc -shared link_preload sharedlibext .dll tcl_platform(byteOrder) littleEndian tcl_platform(machine) intel tcl_platform(os) Windows NT tcl_platform(osVersion) 5.0 tcl_platform(platform) windows tcl_platform(wordSize) 4 } # Cross-compile for ARM (n770/Zaurus/etc) using Scratchbox et al param linux-arm { tcl_platform(byteOrder) littleEndian tcl_platform(machine) arm tcl_platform(os) Linux tcl_platform(osVersion) 2.6 tcl_platform(platform) unix tcl_platform(wordSize) 4 } # hpux itanium, native cc, 32 and 64bit builds. # +z <=> -fPIC on hpux. # +DD64 invokes the 64bit mode. param hpux-ia64_32 { compile cc -c +z link ld -b preproc_define cc -E preproc_enum cc -E } param hpux-ia64 { compile cc -c +z +DD64 link ld -b preproc_define cc -E preproc_enum cc -E } # hpux, itanium, gcc # This works only if the -lgcc for 64bit is somewhere reachable. # hpux-ia64 gcc -c -fPIC -mlp64 # aix, rs6000/powerpc, native cc, 32bit build # The link line is pretty much copied from Tcl. # NOTE: ldAix was copied from Tcl into a directory in the PATH. # It might make sense to stuff this file into critcl and then copy it out when # needed, either into a fixed place, or tempdir. In the latter case the link # line needs some way of getting the value substituted into it. I have no # idea of the critcl config allows that, and if yes, nor how. # cc_r = something with thread-enabled. better use it than cc and have things # fail. param aix-powerpc { compile cc_r -c -O link ldAix /bin/ld -bhalt:4 -bM:SRE -bE:lib.exp -H512 -T512 -bnoentry -lm -lc preproc_define cc -E preproc_enum cc -E } variable preload {} ;# libs to preload variable libfile {} ;# libs proc compile {ns args} { set copts "" set cflags "" set libs "" set ldflags "" if {![info exists platform] || $platform eq ""} { set platform [::platform::generic] } # find matching parameter sets variable param set matches {} dict for {n v} $param { #puts stderr "pmatch $n $platform: [string match $n $platform]" if {[string match $n $platform]} { lappend matches [string map {* \xff} $n] } } # roughly sort the matches into ascending order set matches [lsort -dictionary $matches] set matches [string map {\xff *} $matches] # combine matching parameter sets set p {} foreach n $matches { set p [dict merge $p [dict get $param $n]] } # get the C source and populate the command line set source [$ns generate] set sfd [file tempfile src]; puts $sfd $source; close $sfd set obj $src; file rename $src $src.c; append src .c dict with p { set cmdline "$compile $cflags $threadflags $tclstubs $copts" set obj $obj$object append cmdline " " [string map [list %OUTFILE% $obj] $output] # add the Tk stuff if {[dict exists $args tk] && [dict get $args tk]} { append cmdline " $tkstubs" } if {![dict exists $args optimize] || ![dict get $args optimize]} { append cmdline " $optimize" } if {![dict exists $args symbols] || [dict get $args symbols]} { append cmdline " $debug_symbols" } append cmdline " " [list $src] ;# record the source file name in the cmdline } puts stderr "Compiling: $cmdline" if {[catch { exec {*}$cmdline } result eo]} { error "Compilation '$cmdline' failed: '$result' ($eo)" } # link the resultant .o file into an .so file lappend objs $obj set target [$ns package] set libs {-L/usr/lib -ltclstub8.5} # -ltcl8.6 dict with p { set cmdline $link variable preload if {[llength $preload]} { append cmdline " $link_preload" } set outfile $target$sharedlibext set ldout [string map [list %OUTFILE% $outfile] $ldoutput] if {$ldout eq ""} { set ldout [string map [list %OUTFILE% $outfile] $output] } if {![dict exists $args symbols] || [dict get $args symbols]} { append cmdline " $link_debug $ldout" } else { append cmdline " $strip $link_release $ldout" } variable libfile append cmdline " " $libfile append cmdline " " $objs append cmdline " $libs $ldflags" } puts stderr "linking: $cmdline" if {[catch { exec {*}$cmdline } result eo]} { error "Linking '$cmdline' failed: '$result' ($eo)" } return $obj } ::namespace export -clear * ::namespace ensemble create -subcommands {} } if {[info exists argv0] && ($argv0 eq [info script])} { package require C C proc add {int x int y} int { return x + y; } C proc cube {int x} int { return x * x * x; } C package Junk puts [CC compile [C namespace]] load Junk.so puts [add 345 123] puts [cube 99] }
AMG: To get this to work with Tcl 8.6 CVS HEAd compiled with --enable-symbols in MinGW, I had to make the following changes:
I don't know the "right" way to make any of these changes; obviously my patched CC.tcl will only work in my exact configuration. I tried adding new "param win32" and "param win32-ix86" blocks, but -fPIC still got passed to the compiler.
Also. What, if anything, has to be done to get Tk support?