[gambit-list] Dump a .c file into another program's structure and compile it from another compiler?

Marc Feeley feeley at iro.umontreal.ca
Wed Feb 11 09:31:04 EST 2015


> On Feb 10, 2015, at 11:40 PM, Colin Gilbert <colingilbert86 at gmail.com> wrote:
> 
> Hi,
> 
> Pardon the silly noob question, but I've been trying to use Gambit to quickly write up a small submodule, and then use each target's native compiler to embed it into the build. Unfortunately, I am getting link errors:
> 
> Is my my mini program:
> hello.scm: (display "hello") (newline)
> 
> Here is what happens when I try to use it.
> 
> >> gsc -c hello.scm
> *** INFO -- loading syntax expander
> 
> >> gcc hello.c
> 
> cc hello.c
> /usr/lib/gcc/x86_64-pc-linux-gnu/4.8.3/../../../../lib64/crt1.o: In function `_start':
> (.text+0x20): undefined reference to `main'
> /tmp/ccpGbiFh.o: In function `___H__20_hello':
> hello.c:(.text+0x8d): undefined reference to `___gstate0'
> hello.c:(.text+0xd4): undefined reference to `___gstate0'
> hello.c:(.text+0xee): undefined reference to `___G_display'
> hello.c:(.text+0x132): undefined reference to `___G_display'
> hello.c:(.text+0x144): undefined reference to `___gstate0'
> hello.c:(.text+0x176): undefined reference to `___gstate0'
> hello.c:(.text+0x194): undefined reference to `___G_newline'
> hello.c:(.text+0x1d5): undefined reference to `___G_newline'
> hello.c:(.text+0x1e7): undefined reference to `___gstate0'
> /tmp/ccpGbiFh.o: In function `___setup_mod':
> hello.c:(.text+0x25c): undefined reference to `___G__20_hello'
> /tmp/ccpGbiFh.o: In function `___init_mod':
> hello.c:(.text+0x26f): undefined reference to `___gstate0'
> hello.c:(.text+0x281): undefined reference to `___G__20_hello'
> /tmp/ccpGbiFh.o: In function `____20_hello':
> hello.c:(.text+0x29b): undefined reference to `___S_hello'
> collect2: error: ld returned 1 exit status
> 
> I tried using -link, -flat,-link -flat but no real difference.
> 
> What files need to be present before you can compile the code natively?

The default Gambit-C build procedure is designed for building on the same type of platform where the executable will be run.  For portability to different platforms, the build procedure uses a “configure” script that determines various properties of the platform (the existence of various system header files, the width of pointers, the type of operating system, etc).  The “configure” script will adapt the makefiles and also fill in some blanks in include/gambit.h.in to generate the Gambit header file include/gambit.h (and similarly for include/config.h.in).

In a situation with multiple target platforms, the configure script would have to be run on each target platform to determine the properties of the platform and adapt the include/gambit.h.in file and the include/config.h.in file accordingly for compiling on that platform.

I sense that you are looking for a different approach.  I assume in the following that you want to compile a Scheme app into a set of .c and .h files that you can compile on multiple target platforms with little or no changes and no configure script or equivalent procedure.

Here are two approches.  The first assumes that your target platforms share similar characteristics with the development platform (same OS, same processor word size) so that the gambit.h and config.h files produced by the configure script are OK.  The second approach uses options on the C compiler’s command line to fill in the information that the configure script normally determines.

So we start with compiling Gambit on the development platform:

% mkdir embed
% cd embed
% git clone http://github.com/feeley/gambit.git
% cd gambit
% ./configure --enable-single-host
% make from-scratch
% make install
% cd ..

Now we use the first approach that reuses the development platform’s gambit.h and config.h files.  Note that we compile all the .c files (from the Gambit library and the Scheme app) in one call of the C compiler (this could be changed to a seperate compilation of each .c file).  In any case it takes less than a minute to compile everything (this is with GNU gcc 4.9.2 on a fast machine with an SSD).

% mkdir test1
% cd test1
% echo '(println "hello!")' > hello.scm
% gsc -c hello.scm      # generate hello.c from hello.scm
% gsc -link hello.c     # generate hello_.c from hello.c
% cp ../gambit/include/stamp.h .
% cp ../gambit/include/gambit.h .
% cp ../gambit/include/config.h .
% cp ../gambit/lib/*.c .
% cp ../gambit/lib/*.h .
% time gcc -O1 -DHAVE_CONFIG_H *.c -o hello.exe

real	0m47.653s
user	0m46.124s
sys	0m1.443s
% ./hello.exe
hello!
% cd test1
% ls -l hello.exe
-rwxr-xr-x+ 1 feeley  staff  5187576 Feb 11 08:09 hello.exe
% strip hello.exe
% ls -l hello.exe
-rwxr-xr-x+ 1 feeley  staff  4566440 Feb 11 08:09 hello.exe
% cd ..

Now for the second approach.  Note that the gambit.h file is simply a copy of the gambit.h.in file.  The “blanks” in that file (normally filled in by the configure script) are filled in with C compiler options (-D___VOIDSTAR_WIDTH=8 for a 64 bit processor, D___MAX_CHR=0x10ffff for full Unicode support, etc).  Similarly, the information in the config.h file is specified with C compiler options (-DHAVE_ERRNO_H to indicate that errno.h is available, etc).

% mkdir test2
% cd test2
% echo '(println "hello!")' > hello.scm
% gsc -c hello.scm      # generate hello.c from hello.scm
% gsc -link hello.c     # generate hello_.c from hello.c
% cp ../gambit/include/gambit.h.in gambit.h
% cp ../gambit/include/stamp.h .
% cp ../gambit/lib/*.c .
% cp ../gambit/lib/*.h .
% time gcc -O1 -DHAVE_ERRNO_H -DHAVE_STDLIB_H -DHAVE_STRING_H -D___VOIDSTAR_WIDTH=8 -D___MAX_CHR=0x10ffff -D___BOOL=int -D___SINGLE_VM -D___SINGLE_THREADED_VMS -D___USE_NO_THREAD_SYSTEM -D___NO_THREAD_LOCAL_STORAGE_CLASS -D___LABEL_ACCESS_OLD -D___SINGLE_HOST -D___GAMBCDIR='"/usr/local/Gambit-C"' *.c -o hello.exe

real	0m48.342s
user	0m46.860s
sys	0m1.387s
% ./hello.exe 
hello!
% ls -l hello.exe
-rwxr-xr-x+ 1 feeley  staff  5150656 Feb 11 08:42 hello.exe
% strip hello.exe
% ls -l hello.exe
-rwxr-xr-x+ 1 feeley  staff  4532824 Feb 11 08:43 hello.exe
% cd ..

So once compiled, a Scheme app can be seen as a set of .c and .h files and building the app requires a bit of knowledge of the characteristics of the target platform (but not very much, in fact the only critical one is ___VOIDSTAR_WIDTH = sizeof(void*), which has to be known at C macro expansion time to adapt some of the macros defined in gambit.h).

Note that the need to specify -D___LABEL_ACCESS_OLD and -D___GAMBCDIR='"/usr/local/Gambit-C"' (and maybe a few others) will go away in a future release of Gambit as they could have default values.

Marc

-------------- next part --------------
A non-text attachment was scrubbed...
Name: smime.p7s
Type: application/pkcs7-signature
Size: 4839 bytes
Desc: not available
URL: <http://mailman.iro.umontreal.ca/pipermail/gambit-list/attachments/20150211/531e1584/attachment-0001.bin>


More information about the Gambit-list mailing list