I've been thinking about modularity problems (aside from actual module systems). One of the problems I have is that invoking gsc from a Makefile is pretty rough because of dependencies. I almost always end up with files not recompiling.
I'm thinking of a simple build tool which takes a directory structure like so:
bin/ lib/ test/
And just does the right thing. All the lib files compiled independently, with dependencies calculated, files which have a hash mark in them are skipped. The resulting files are linked against each program in bin/ and test/, and test programs are run.
Just this much functionality would be a huge improvement for my workflow.
Deisgn thoughts? -Jason
Afficher les réponses par date
Hm.
Wouldn't this fit well into what a [programmable] module system does (i.e. calculates dependencies and invokes compiler)?
Do you have closer thoughts on how this build/compilation process can work - like, what's the process and the conditionals
2013/2/28 Jason Felice jason.m.felice@gmail.com
I've been thinking about modularity problems (aside from actual module systems). One of the problems I have is that invoking gsc from a Makefile is pretty rough because of dependencies. I almost always end up with files not recompiling.
I'm thinking of a simple build tool which takes a directory structure like so:
bin/ lib/ test/
And just does the right thing. All the lib files compiled independently, with dependencies calculated, files which have a hash mark in them are skipped. The resulting files are linked against each program in bin/ and test/, and test programs are run.
Just this much functionality would be a huge improvement for my workflow.
Deisgn thoughts? -Jason
Gambit-list mailing list Gambit-list@iro.umontreal.ca https://webmail.iro.umontreal.ca/mailman/listinfo/gambit-list
On 2013-02-28, at 11:03 AM, Jason Felice jason.m.felice@gmail.com wrote:
I've been thinking about modularity problems (aside from actual module systems). One of the problems I have is that invoking gsc from a Makefile is pretty rough because of dependencies. I almost always end up with files not recompiling.
Before suggesting a better design I would like to understand this problem. Can you give an example, or your current makefile, error logs, etc?
Marc
Jason (and Marc)
What I tend to do is to put the Scheme source in a single directory, with a Makefile.
The Makefile dependency is -scm -> .o1
The rule deletes any .o1 (with rm -f to avoid errors on a clean build). Note that the issue is the CHANGING of the target (Marc? is it possible to FORCE an output as .o?). Anyway, forcing an output file to .o DOESN'T work:
[fred@dejah blib]$ cp amb.o1 amb.o [fred@dejah blib]$ gsi Gambit v4.6.6
(load "amb.o")
*** ERROR IN "amb.o"@1.5 -- Illegal character: #\x02 1>
A simple change, designed around Makefiles, instead of interactive use.
It should be possible to collect the .o (well, .o1) files into a library (and, using the unix/linux ar tool it is). BUT, this is particularly annoying. Basically, assume that I have n .o1 files as part of a library:
ar q new.o1 *.o1
should (and does) collect the object files into an archive, but we can't do anything with it --
[fred@dejah blib]$ gsi Gambit v4.6.6
(load "new.o1")
*** WARNING -- Could not find C function: "____20_new_2e_o1" *** ERROR IN (console)@1.1 -- /export/home/fred/Projects/blib/new.o1: invalid ELF header (load "new.o1") 1>
Gambit doesn't handle ar archives! (only ELF objects). This would be a simple enhancement (and is easily butchered in, if load() is overriden). "ar t" will give the members, Each can be easily extracted, and then loaded independently. I haven't yet butchered it though...
This change would seriously help ME :) because I can then easily distribute applications (as the exe and an ar archive with the .o1 files, instead of 50 to 100 .o1 files).
For library delivery (in the Makefile) I build links from a ~~lib (or subdirectory) to the build directory (filename#.scm and filename.o1 are linked, for access by gsi). I then manually load the required components (usually via an include() in the source file).
All this works great for MY personal machine, but it is still a serious bear to try to distribute binary applications.
So, to recap:
- gsi should be able to load ar archives as well as elf - gsc should be able to compile to a fixed extension - gsi shouldn't barf on an attempted load of ".o"
As an "advanced" feature, a gsc option to scan source, looking for (load) (##load) (include) (##include) and building Makefile dependencies (I use a hack for this, using sed). Since these can be built by (define-macro), it would be useful to have this done by the compiler itself. This doesn't help for dynamically constructed (load), which can be delayed until run-time, and my solution especially falls down in this case. Doing the generation at compile-time would eliminate this problem for me.
- gsc option to generate dependencies for Makefiles
After these, we can examine other issues with "modules", proper static libraries, and proper shared libraries -- but those are very complex.
Just my nickels worth.
FredW
On Thu, 2013-02-28 at 10:03 -0600, Jason Felice wrote:
Gambit-list mailing list Gambit-list@iro.umontreal.ca https://webmail.iro.umontreal.ca/mailman/listinfo/gambit-list
On 2013-03-01, at 2:13 PM, Fred Weigel fred.weigel@zylog.ca wrote:
Jason (and Marc)
What I tend to do is to put the Scheme source in a single directory, with a Makefile.
The Makefile dependency is -scm -> .o1
The rule deletes any .o1 (with rm -f to avoid errors on a clean build). Note that the issue is the CHANGING of the target (Marc? is it possible to FORCE an output as .o?).
Yes...
gsc -o example.o1 example.scm
Anyway, forcing an output file to .o DOESN'T work:
[fred@dejah blib]$ cp amb.o1 amb.o [fred@dejah blib]$ gsi Gambit v4.6.6
(load "amb.o")
*** ERROR IN "amb.o"@1.5 -- Illegal character: #\x02 1>
This doesn't work because "load" uses the file extension to determine if it is loading a compiled file (extension .oN), or source code. Moreover, the name can't be changed after compilation, because the C entry point of the compiled code is derived from the file name. The Gambit runtime uses dlopen (or equivalent) where it must know the C function name of the entry point to get a pointer to the correct function.
A simple change, designed around Makefiles, instead of interactive use.
It should be possible to collect the .o (well, .o1) files into a library (and, using the unix/linux ar tool it is). BUT, this is particularly annoying. Basically, assume that I have n .o1 files as part of a library:
ar q new.o1 *.o1
should (and does) collect the object files into an archive, but we can't do anything with it --
[fred@dejah blib]$ gsi Gambit v4.6.6
(load "new.o1")
*** WARNING -- Could not find C function: "____20_new_2e_o1" *** ERROR IN (console)@1.1 -- /export/home/fred/Projects/blib/new.o1: invalid ELF header (load "new.o1") 1>
Gambit doesn't handle ar archives! (only ELF objects). This would be a simple enhancement (and is easily butchered in, if load() is overriden). "ar t" will give the members, Each can be easily extracted, and then loaded independently. I haven't yet butchered it though...
This change would seriously help ME :) because I can then easily distribute applications (as the exe and an ar archive with the .o1 files, instead of 50 to 100 .o1 files).
I don't see why you don't simply distribute your app as a tar/zip file which expands into a directory structure where all the .o1 files are in a subdirectory. And then just load things from that subdirectory.
Wouldn't it be simpler (for the end user) to statically link all of your compiled files into a single executable? That's what I usually do, in part because it avoids installation problems related to paths. In that case the makefile needs to:
- compile L.scm to L.c for each library file L.scm (i.e. gsc -c L.scm) - compile the main program M.scm to M.c (i.e. gsc -c M.scm) - link with gsc all the L.c files and M.c file to M_.c file (i.e. gsc -link L1.c L2.c L3.c M.c) - compile L.c to L.o for each library file L.scm (i.e. gcc -Igambit_install_dir/include -c L.c) - compile M.c to M.o and M_.c to M_.o - link with the C compiler all the L.o files with M.o and M_.o to produce M.exe
For library delivery (in the Makefile) I build links from a ~~lib (or subdirectory) to the build directory (filename#.scm and filename.o1 are linked, for access by gsi). I then manually load the required components (usually via an include() in the source file).
All this works great for MY personal machine, but it is still a serious bear to try to distribute binary applications.
So, to recap:
- gsi should be able to load ar archives as well as elf
What syntax would you suggest?
(load "path/archive(module.o1)")
- gsc should be able to compile to a fixed extension
It does already.
- gsi shouldn't barf on an attempted load of ".o"
Why? What if the user used ".o" as an extension for their source files? Should gsi barf on ".obj" also? And ".ss" and ".SCM", etc?
As an "advanced" feature, a gsc option to scan source, looking for (load) (##load) (include) (##include) and building Makefile dependencies (I use a hack for this, using sed). Since these can be built by (define-macro), it would be useful to have this done by the compiler itself. This doesn't help for dynamically constructed (load), which can be delayed until run-time, and my solution especially falls down in this case. Doing the generation at compile-time would eliminate this problem for me.
Here's an implementation of what you want. It keeps a table of all the arguments to "load" and could be easily extended to "include", etc.
(define-macro (eval-at-expansion-time . exprs) (eval (cons 'begin exprs)) '(begin))
(eval-at-expansion-time
(define table-of-loaded-files (make-table))
(##add-exit-job! (lambda () (pretty-print (cons 'loaded-files: (map car (table->list table-of-loaded-files)))))))
(define load-orig load)
(define-macro (load file) (table-set! table-of-loaded-files file #t) `(load-orig ,file))
- gsc option to generate dependencies for Makefiles
This is a bit too platform specific (why a makefile, and not scons, cmake, etc). I would prefer if this was a tool external to gsc, perhaps using information obtained by gsc.
After these, we can examine other issues with "modules", proper static libraries, and proper shared libraries -- but those are very complex.
Just my nickels worth.
FredW
Marc
Marc
Thanks for the info on "-o name.o1" I wasn't aware that I could do that. It simplifies the Makefiles.
Also thanks for the dependency finder. I'll play with the idea (though I do see one issue with my workflow).
FredW
----- Original Message ----- From: "Marc Feeley" feeley@iro.umontreal.ca To: "Fred Weigel" fred.weigel@zylog.ca Cc: "Gambit List" gambit-list@iro.umontreal.ca Sent: Friday, March 1, 2013 3:46:25 PM Subject: Re: [gambit-list] Build tool, directory structure
On 2013-03-01, at 2:13 PM, Fred Weigel fred.weigel@zylog.ca wrote:
Jason (and Marc)
What I tend to do is to put the Scheme source in a single directory, with a Makefile.
The Makefile dependency is -scm -> .o1
The rule deletes any .o1 (with rm -f to avoid errors on a clean build). Note that the issue is the CHANGING of the target (Marc? is it possible to FORCE an output as .o?).
Yes...
gsc -o example.o1 example.scm
Anyway, forcing an output file to .o DOESN'T work:
[fred@dejah blib]$ cp amb.o1 amb.o [fred@dejah blib]$ gsi Gambit v4.6.6
(load "amb.o")
*** ERROR IN "amb.o"@1.5 -- Illegal character: #\x02 1>
This doesn't work because "load" uses the file extension to determine if it is loading a compiled file (extension .oN), or source code. Moreover, the name can't be changed after compilation, because the C entry point of the compiled code is derived from the file name. The Gambit runtime uses dlopen (or equivalent) where it must know the C function name of the entry point to get a pointer to the correct function.
A simple change, designed around Makefiles, instead of interactive use.
It should be possible to collect the .o (well, .o1) files into a library (and, using the unix/linux ar tool it is). BUT, this is particularly annoying. Basically, assume that I have n .o1 files as part of a library:
ar q new.o1 *.o1
should (and does) collect the object files into an archive, but we can't do anything with it --
[fred@dejah blib]$ gsi Gambit v4.6.6
(load "new.o1")
*** WARNING -- Could not find C function: "____20_new_2e_o1" *** ERROR IN (console)@1.1 -- /export/home/fred/Projects/blib/new.o1: invalid ELF header (load "new.o1") 1>
Gambit doesn't handle ar archives! (only ELF objects). This would be a simple enhancement (and is easily butchered in, if load() is overriden). "ar t" will give the members, Each can be easily extracted, and then loaded independently. I haven't yet butchered it though...
This change would seriously help ME :) because I can then easily distribute applications (as the exe and an ar archive with the .o1 files, instead of 50 to 100 .o1 files).
I don't see why you don't simply distribute your app as a tar/zip file which expands into a directory structure where all the .o1 files are in a subdirectory. And then just load things from that subdirectory.
Wouldn't it be simpler (for the end user) to statically link all of your compiled files into a single executable? That's what I usually do, in part because it avoids installation problems related to paths. In that case the makefile needs to:
- compile L.scm to L.c for each library file L.scm (i.e. gsc -c L.scm) - compile the main program M.scm to M.c (i.e. gsc -c M.scm) - link with gsc all the L.c files and M.c file to M_.c file (i.e. gsc -link L1.c L2.c L3.c M.c) - compile L.c to L.o for each library file L.scm (i.e. gcc -Igambit_install_dir/include -c L.c) - compile M.c to M.o and M_.c to M_.o - link with the C compiler all the L.o files with M.o and M_.o to produce M.exe
For library delivery (in the Makefile) I build links from a ~~lib (or subdirectory) to the build directory (filename#.scm and filename.o1 are linked, for access by gsi). I then manually load the required components (usually via an include() in the source file).
All this works great for MY personal machine, but it is still a serious bear to try to distribute binary applications.
So, to recap:
- gsi should be able to load ar archives as well as elf
What syntax would you suggest?
(load "path/archive(module.o1)")
- gsc should be able to compile to a fixed extension
It does already.
- gsi shouldn't barf on an attempted load of ".o"
Why? What if the user used ".o" as an extension for their source files? Should gsi barf on ".obj" also? And ".ss" and ".SCM", etc?
As an "advanced" feature, a gsc option to scan source, looking for (load) (##load) (include) (##include) and building Makefile dependencies (I use a hack for this, using sed). Since these can be built by (define-macro), it would be useful to have this done by the compiler itself. This doesn't help for dynamically constructed (load), which can be delayed until run-time, and my solution especially falls down in this case. Doing the generation at compile-time would eliminate this problem for me.
Here's an implementation of what you want. It keeps a table of all the arguments to "load" and could be easily extended to "include", etc.
(define-macro (eval-at-expansion-time . exprs) (eval (cons 'begin exprs)) '(begin))
(eval-at-expansion-time
(define table-of-loaded-files (make-table))
(##add-exit-job! (lambda () (pretty-print (cons 'loaded-files: (map car (table->list table-of-loaded-files)))))))
(define load-orig load)
(define-macro (load file) (table-set! table-of-loaded-files file #t) `(load-orig ,file))
- gsc option to generate dependencies for Makefiles
This is a bit too platform specific (why a makefile, and not scons, cmake, etc). I would prefer if this was a tool external to gsc, perhaps using information obtained by gsc.
After these, we can examine other issues with "modules", proper static libraries, and proper shared libraries -- but those are very complex.
Just my nickels worth.
FredW
Marc
_______________________________________________ Gambit-list mailing list Gambit-list@iro.umontreal.ca https://webmail.iro.umontreal.ca/mailman/listinfo/gambit-list
Marc
Ok, thought about it some more.
I am not really a "Windows Guy", so there may be issues that I haven't examined... But, that aside:
the syntax archive(member) for load/include would be perfect:
(load "~~lib/mylibrary(member)")
This works with other uses of archives. Of course, the member could be ELF (object) or scheme source.
Next, it strikes me that ELF (PE?) format can be detected, and the NAME shouldn't be the key. You are using the name to find the entry point -- but multiple objects that are loaded can have the same names. Specifically, when a .so is loaded, the _init() function is called, and these don't conflict at all. But, there may have been issues UNLOADING objects (on some platforms), which is where your .oN solution came from in the first place.
So, I can see that, if the objects are NOT unloaded, the .oN convention allows continued interactive development.
If I can suggest something a little off that path -- if the target is .o (or another distinguished name, not .oN), that the entry component (which will end up being a pointer anyway with dlopen() and friends) can have the same name, no matter what module is is. This would not allow "reloading" at all in the sense of interactive development, but would behave more like a Unix .so component. It would allow the objects so compiled to be freely renamed.
Now, this can interact well with identifying ARCHIVE/OBJECT and anything else as SOURCE.
And, yes, I agree that I should have an installer that simply untars the application into a directory and runs it (I don't generally care enough to statically link the whole thing anyway, these are not "mass market" things).