PreviousUpNext

5.3.16  Multi-file Projects: Compiling a Stand-Alone Executable

To develop useful multi-file applications, you will also need to know how to compile a stand-alone executable which can be invoked from the command line or scripts like any other Linux executable.

In this section we will present a complete worked-out example of implementing a simple clone of the Linux factor program, which prints out the prime factorization of each argument it is given.

Our solution consists of the following four files:

Using these we will compile a factor executable image using the standard Mythryl /usr/bin/build-an-executable-mythryl-heap-image script which gets installed with the other standard Mythryl programs when you do a make install.

The following transcript shows the contents of the required files and also the compilation process:

    linux$ cat factor.api

    api Factor {
        factors: Int -> List(Int);
    };

    linux$ cat factor.pkg

    package factor {

        fun factor_helper (i, trial_divisor, known_factors) = {

            if (trial_divisor > i)   reverse known_factors;
            else
                if (i % trial_divisor != 0)   factor_helper (i,               trial_divisor + 1,                  known_factors);
                else                          factor_helper (i/trial_divisor, trial_divisor,      trial_divisor ! known_factors);
                fi;
            fi;
        };

        fun factors( i ) = {
            if (i <= 1)  [i];
            else         factor_helper (i, 2, []);
            fi;
        };
    };

    linux$ cat main.pkg

    package main:  api {
                       main: ((String, List( String )))   ->   winix__premicrothread::process::Status;
                   }
    {
        include package   trap_control_c;         # trap_control_c        is from   src/lib/std/trap-control-c.pkg

        fun print_to_stderr msg
            =
            file::write
                (
                  file::stderr,
                  string::cat msg
                );

        fun print_factors( number, factors ) = {
            printf "%d:" number;
            map (printf " %d") factors;
            printf "\n";
        };

        fun factor_number( arg ) = {
            number = the (int::from_string arg);
            print_factors( number, factor::factors( number ) );
        };

        fun factor_args args = {
            apply factor_number args;
        };

        fun main (name, args) = {

            fun run_program ()
                =
                factor_args args;

            {   catch_interrupt_signal  run_program;
                winix__premicrothread::process::success;
            }
            except
                CONTROL_C_SIGNAL
                    =>
                    {   print_to_stderr [name, ": Interrupt\n"];
                        winix__premicrothread::process::failure;
                    };

                any =>
                    {   print_to_stderr [   name,
                                ": uncaught exception ",
                                exceptions::exception_message any,
                                "\n"
                            ];

                        winix__premicrothread::process::failure;
                    };
            end ;
        };
    };

    linux$ cat factor.lib

    LIBRARY_EXPORTS

            api Factor
            pkg factor
            pkg main

    LIBRARY_COMPONENTS

            $ROOT/src/lib/std/standard.lib

            factor.api
            factor.pkg

            main.pkg

    linux$ build-an-executable-mythryl-heap-image factor.lib main::main
     _build-an-executable-mythryl-heap-image:   Starting.
     _build-an-executable-mythryl-heap-image:   main=main::main (III)
     _build-an-executable-mythryl-heap-image:   main=main::main (after sed)
     _build-an-executable-mythryl-heap-image:   Listing tmp-makelib-pid-26077-export.pkg:

    pkg xyzzy_plugh { my _ = lib7::spawn_to_disk ("factor", main::main); };

     _build-an-executable-mythryl-heap-image:   Listing .lib file:

    SUBLIBRARY_EXPORTS pkg xyzzy_plugh SUBLIBRARY_COMPONENTS $ROOT/src/lib/std/standard.lib factor.lib tmp-makelib-pid-26077-export.pkg

     _build-an-executable-mythryl-heap-image:   Doing:                  "/usr/bin/mythryld"  --build-an-executable-mythryl-heap-image  "factor.lib" "tmp-makelib-pid-26077-export.lib" "factor" "tmp-makelib-pid-26077.COMPILED_FILES_TO_LOAD" "tmp-makelib-pid-26077.LINKARGS"
                parse/libfile-parser-g.pkg:   Reading   make   file   factor.lib                                            on behalf of <toplevel>
  app/makelib/compilable/thawedlib-tome.pkg:   Parsing   source file   factor.api
  app/makelib/compilable/thawedlib-tome.pkg:   Parsing   source file   factor.pkg
  app/makelib/compilable/thawedlib-tome.pkg:   Parsing   source file   main.pkg
          .../compile/compile-in-dependency-order-g.pkg:   Compiling source file   factor.api                                              to object file   factor.api.compiled
          .../compile/compile-in-dependency-order-g.pkg:   Compiling source file   factor.pkg                                              to object file   factor.pkg.compiled
          .../compile/compile-in-dependency-order-g.pkg:   Compiling source file   main.pkg                                                to object file   main.pkg.compiled
                parse/libfile-parser-g.pkg:   Reading   make   file   tmp-makelib-pid-26077-export.lib                        on behalf of <toplevel>
                parse/libfile-parser-g.pkg:   Reading   make   file   factor.lib                                            on behalf of <toplevel>
  app/makelib/compilable/thawedlib-tome.pkg:   Parsing   source file   tmp-makelib-pid-26077-export.pkg
          .../compile/compile-in-dependency-order-g.pkg:   Compiling source file   tmp-makelib-pid-26077-export.pkg                          to object file   tmp-makelib-pid-26077-export.pkg.compiled

              src/app/makelib/main/makelib-g.pkg:   Creating file 'tmp-makelib-pid-26077.COMPILED_FILES_TO_LOAD'


              src/app/makelib/main/makelib-g.pkg:   Creating file 'tmp-makelib-pid-26077.LINKARGS'

     _build-an-executable-mythryl-heap-image:   Doing:                        "/usr/bin/mythryl-ld" `cat "tmp-makelib-pid-26077.LINKARGS"`

    ----------------------------------------------------
                              bin/mythryl-ld:   Starting
                              bin/mythryl-ld:   Exec()'ing                              /pub/home/cynbe/src/mythryl/mythryl7/mythryl7.110.58/mythryl7.110.58/bin/mythryl-runtime-intel32 --runtime-compiledfiles-to-load=tmp-makelib-pid-26077.COMPILED_FILES_TO_LOAD --runtime-heap=mythryld 

   src/c/main/load-compiledfiles.c:   Writing load log to               mythryld-26088.load.log

   src/c/main/load-compiledfiles.c:   Reading   file          tmp-makelib-pid-26077.COMPILED_FILES_TO_LOAD

        .../lib/heap/export-fun.c:   Writing   executable (heap image) /pub/home/cynbe/src/mythryl/mythryl7/mythryl7.110.58/mythryl7.110.58/factor

    linux$ ./factor 23 24
    23: 23
    24: 2 2 2 3

    linux$

The above code is largely self-explanatory; you should have little difficulty adapting it to your own needs.

For your convenience, the above code is shipped in the src/app/tut/factor/ directory in the Mythryl source code distribution.

For a serious application, you will probably want to put the illustrated build-an-executable-mythryl-heap-image call in your application’s Linux Makefile. (The Mythryl makelib is not intended to replace Linux make, but rather to work with it in complementary fashion. Each does well things the other does poorly.)

The main.pkg file is mostly boilerplate that you can use unchanged in your own application except for changing the run_program function to run the code appropriate to your application.

A serious application will have many more source files and perhaps application-specific .lib libraries. Just add them to the factor.lib file (presumably appropriately renamed for your application) and Mythryl’s makelib will take care of compiling everything in the right order. (Unlike Linux make, Mythryl makelib deduces needed dependency relationships directly from the source code.)

A nontrivial application will probably support various command line options. You may wish to process them using the process_commandline package, which is a Mythryl port of the GNU getopt C package.


Comments and suggestions to: bugs@mythryl.org

PreviousUpNext