Closed dandorat closed 3 years ago
Why is formdps.c written in C?
I needed to pass arguments from Makefile to a programming language and then generate some commands with the help of that language and then make system calls to shell with those commands. C looked like a good choice and I knew how to do this in C also.
Here's a sketch of how to do this in Racket (formdps.rkt):
#lang racket
(provide main)
(define (main arg1 arg2)
(printf "arg1: ~a\n" arg1)
(printf "arg2: ~a\n" arg2)
(system "ls"))
In the Makefile:
%.run: %.o
racket -t formdps.rkt -m make $@
Yes, it is similar to C. But I also use fopen, fgetc, rewind, and putc in the C code. I need to look up the corresponding functions in Racket and the behavior of those functions. Will do that now.
I think the right approach is to avoid these things entirely. I will try to push a sketch of how to accomplish this later today.
Ok, I'll think about it also.
Following your sketch above, I wrote formdps.rkt
as follows and replaced the C file with it. The tests work well.
#lang racket
(provide main)
(define (main arg1 arg2)
(if (equal? arg1 "mv")
(let ((str_run (substring arg2 0 (- (string-length arg2) 1))))
(begin (system (string-append "mv " arg2 " " str_run)) (void)))
(begin (system "touch modulefiles")
(let ((in (open-input-file "modulefiles")))
(begin
(let ((str (read-line in)))
(if (eof-object? str)
(void)
(if (equal? (string-ref str 0) #\y)
(begin (string-set! str 0 #\ )
(system (string-append "make " str)))
(void))))
(close-input-port in)))
(let ((out (open-output-file "modulefiles" #:exists 'update)))
(begin
(file-position out 0)
(display " " out)
(close-output-port out)))
(begin (system (string-append arg1 " " arg2 "2")) (void)))))
Comments on previous pull request are also included bellow.
The reason for problem with the tests when putting all five
exmod*.rkt
files in the test folder was related to that two of those files were modules that have an expression at the end of them, and three were modules that have provide, require, and definitions, but no expression; for example,exmod2.rkt
is with no expressions at the end as follows:make
exmod2.s
worked, but compiling the executableexmod2.run
and running it did not work because the module returned no value. So now it returns void and the tests can now be done on these modules also.The reason that the message "cat: modulefiles: No such file or directory" printed for all files was that when
compile-file -m %.rkt > %.s
is done,modules.rkt
runs at this step and creates the filemodulefiles
with the list of the.o files
for the required modules. Then, the list in this file is used in make by$(shell cat modulefiles)
. At that time the file is available and this does not cause any problem with the compilation. Make initially forms a dependency graph of targets and prerequisites and because$(shell cat modulesfiles)
was in the prerequisites of a target, this message was produced while there is no real error.Makefile
andformdps.c
was modified such that$(shell cat modulefiles)
is not in make prerequisites and the message "cat: modulefiles: No such file or directory" is not generated byMakefile
now.In addition, I found out that when a module is required in a file in racket, racket runs the module, and if the module has an expression at the end, it evaluates the expression and outputs the result. Currently this feature is not supported in our module system. So, I removed the expression at the end of
exmod1.rkt
which is one of the modules required byexmod0.rkt
:exmod0.rkt
:exmod1.rkt
:In addition, I did updates in
parse.rkt
andmodules.rkt
such that modules with(provide (all-defined-out))
, and modules with just provide and no require, can also be compiled. Addedexmod5.rkt
andexmod6.rkt
to test these features:exmod5.rkt
exmod6.rkt
Previous comments:
Modules
Implemented modules by adding the following:
modules.rkt
fileformdps.c
)Makefile
to callformdps.c
which then via a system call invokesmake
again (to allow the module dependencies to be calculated inmodules.rkt
to produce a list of.o files
of the needed modules and also to compile the.s files
of the modules in this step before the rest of the recipe in theMakefile
is carried out)ast.rkt
,parse.rkt
,compile-file.rkt
,externs.rkt
, andcompile.rkt
.modules.rkt
calculates and stores the directed graph of module dependencies. If there is a cycle in this graph,modules.rkt
detects this and produces an error.Currently, the following formats for the modules are supported:
Example modules
exmod0.rkt
,exmod1.rkt
,exmod2.rkt
,exmod3.rkt
, andexmod4.rkt
added.Exmod0.rkt
has the format(begin (require "filename.rkt" ...) defines e)
and in this example it is used as the root file to be compiled and for the expressione
to be evaluated.If a module is the root file, the expression
e
is included in the compilation. But if a module is not the root file and it has formats 3 and 4, during the compilation the information on imports and exports is included in the compilation, and thedefines
are compiled, but the expressione
is not compiled.Example Run
Executing
make exmod0.run
will first run the commandracket -t compile-file.rkt -m exmod0.rkt > exmod0.s
. During this,compile-file.rkt
callsmodules.rkt
, which calculates module dependencies, does the compilation of the.s files
for the other modules so thatcompile-file.rkt
is not called for them later by the Makefile, and writes the names of the.o files
for the modules that need to be created in a file calledmodulefiles
.Then, the following are done:
nasm -f $(format) -o exmod0.o exmod0.s
to formexmod0.o
./formdps.c make exmod0.run
to make a system call:make exmod0.run2
%.run2
in theMakefile
, the following files are created: the.o files
for the rest of the modules (based on the list in modulefiles),runtime.o
, and the executableexmod0.run2
./formdps.c mv exmod0.run2
to renameexmod0.run2
toexmod0.run
.Then, running the executable
./exmod0.run
will produce the correct result 10.Optionally, a file called
modulesgraph
can be created bymodules.rkt
for information about the directed graph of module dependencies in adjacency list format for the last compilation.Regarding
formdps.c
In the original Makefile, we have this rule:
%.run: %.o runtime.o
gcc runtime.o $< -o $@ $(libs) -lm
I want the rule for making
%.o
be done before the rule for makingruntime.o
is done, so that the command:racket -t compile-file.rkt -m $< > $@
for makingrootfile.s
is executed first.This will ensure that
modules.rkt
is executed calculating the imports and exports, making the.s files
for the required modules incorporating this, and listing the.o files
needed for these required modules in the temporary file modulefiles.Then, the rule for making
runtime.o
should be done which will start with making these listed.o files
and then links them tothe rest of .o files
to makeruntime.o
.As far as I checked, there is no facility in Make for enforcing that the rule for making
%.o
is done beforeruntime.o
. Hence, the use offormdps.c
to ensure this sequence. If there is a way to do that in Make, then we can skipformdps.c
.Regarding modulesgraph
I should have explained that this file is not involved in the compilation and I added it just for informational purposes to give infomation about the graph of modules dependency for the last compilation. As such, it can be removed.
The calculations for each compilation are kept in a list called
mgraph
during the execution ofmodules.rkt
for each compilation. As long as there is no concurrent or parallel compilation and compilation of the two programs are done in sequence, there should not be any issues, because the listmgraph
is not kept after each run ofmodules.rkt
.Modifications for compilation of two programs
In order for the
.o files
created in a previous compilation and the.s files
not to interfere with a subsequent compilation, I modified the following line in theMakefile
:rm -f formdps modulefiles
to also removeruntime.o $(shell cat modulefiles) *.s
I modified
exmod1.rkt
to include an expression(h1 9)
:Then, compiled
exmod0.run
and thenexmod1.run
. This worked well. Then, removedexmod0.run
and compiledexmod0.run
again, which worked well. The following sequence also worked well: compilation ofexmod1.run
, compilation ofexmod0.run
, removal ofexmod1.run
, and then compilation ofexmod1.run
again.Some more information about
modules.rkt
The
modules.rkt
calculates the directed graph of the module dependencies and keeps the graph in a list (mgraph
) during execution. Each element ofmgraph
is a pair of an Mnode struct for that module and a list of file names representing the adacency list of the modules required by the module in that node in the modules graph. The Mnode struct for each module keeps the information about the functions that the module provides, the definitions and the expression.When we want to compile a root module by the command
make <rootmodule>.run
,compile-file.rkt
is called for that root module. Thencompile-file.rkt
callsmodules.rkt
. Thenmodules.rkt
calculates themgraph
and then, by the information in themgraph
, compiles the other modules. For each module, the information on the functions provided by the modules required by that module and the functions that the module provides are incoporated in the compilation. Finally, the control goes back tocompile-file.rkt
returning also the information on the functions provided by the modules required by the root module and then the root module is compiled incorporating this information also.