Module Godi_script


module Godi_script: sig .. end
This module contains library functions for GODI configuration scripts written in OCaml. This is mainly intended for the conf-foo packages.

In order to activate such a script, define the following variables in the driver Makefile of conf-foo:

A number of environment variables are automatically passed to this script:




Primitives


val runcmd : string -> int
Starts the command, waits for its completion, and returns the exit code. Similar to Sys.command, but preferable.
val runcmdf : ('a, unit, string, int) Pervasives.format4 -> 'a
Same as runcmd, but accepts a printf-like format string.
val findcmd : ?path:string list -> string -> string
Returns the absolute location of a command, or raises Not_found. The command is searched in the locations enumerated by the environment variable PATH, by default, or in the locations passed by the path argument.
val system_path : unit -> string list
Returns the locations enumerated by the environment variable PATH
val search_libs_path : unit -> string list
Returns the (command) locations enumerated by the environment variable SEARCH_LIBS
val read_file : string -> string
Reads the file into memory, and returns it as string
val write_file : string -> string -> unit
Writes to the file whose name is passed as first argument the 0contents passed as second argument.
val read_from_cmd : string -> int * string
Starts the command, reads its output (stdout), waits for its completion, and returns both the exit code and the output.
val read_from_cmdf : ('a, unit, string, int * string) Pervasives.format4 -> 'a
Same as read_from_cmd, but accepts a printf-like format string.
val env : string -> string
Returns the named environment variable, or "" if the variable does not exist.
val env_req : string -> string
Returns the named environment variable, or fails if the variable does not exist or is empty.
val env_opt : string -> string option
Returns the named environment variable, or None if the variable is empty or does not exist.

Commandlets



A "commandlet" is a command function that takes a state variable as input and that returns the possibly modified state variable as output. The state variable contains the exit code of the last executed shell command, and optionally a further result value.

Remember that the exit code 0 means that the command was successful.

type 'a cmdstate 
The state with further values of type 'a
val code : 'a cmdstate -> int
The current exit code
val result : 'a cmdstate -> 'a option
The current result value
val return_code : int -> 'a cmdstate -> 'a cmdstate
Returns the modified state where the code is set to the int
val return_result : 'a option -> 'a cmdstate -> 'a cmdstate
Returns the modified state where the result is set
val initial_state : unit -> 'a cmdstate
The initial state has code 0, and no result value
type 'a cmdlet = 'a cmdstate -> 'a cmdstate 
A commandlet is a function taking state and returning state
val cmd : string -> 'a cmdlet
The commandlet that executes the passed command (as string). The exit code is set in the resulting state.
val cmdf : ('a, unit, string, 'b cmdlet) Pervasives.format4 -> 'a
Same as cmd but accepts a printf-like format string
val cmd_output : string -> string cmdlet
The commandlet that executes the passed command (as string), and reads the output of the command (stdout). The exit code is set in the resulting state, and the output is returned as result value.
val cmdf_output : ('a, unit, string, string cmdlet) Pervasives.format4 -> 'a
Same as cmd_output but accepts a printf-like format string
val set_code : int -> 'a cmdlet
The commandlet that sets the exit code to the passed integer
val set_code_from : ('a cmdstate -> int) -> 'a cmdlet
The commandlet that calls the function, and sets the exit code from the integer result of the function.
val set_bool_code : bool -> 'a cmdlet
The commandlet that sets the exit code to 0 if the boolean is true, and to 1 if the boolean is false.
val set_bool_code_from : ('a cmdstate -> bool) -> 'a cmdlet
The commandlet that calls the function, and sets the exit code from the boolean result of the function (as set_code_bool).

This function is useful to call non-commandlets from a sequence of commandlets. For instace, to just print messages:

 
 cmd1 &- 
 set_bool_code_from (fun _ -> printf "Here I am\n"; true) &-
 cmd2 
 

val (&-) : 'a cmdlet -> 'a cmdlet -> 'a cmdlet
Conditional sequencing: If the first commandlet returns the exit code 0, the second commandlet is also executed (like the "&&" shell operator).
val (|-) : 'a cmdlet -> 'a cmdlet -> 'a cmdlet
Conditional sequencing: If the first commandlet returns a non-zero exit code, the second commandlet is also executed (like the "||" shell operator).
val ignore_code : 'a cmdlet -> 'a cmdlet
Executes the commandlet, and ignores the exit code, i.e. sets it always to 0.
val eval : 'a cmdlet -> 'a option
Evaluates a commandlet, and returns the result value. Note that None is always returned if the exit code is non-zero, regardless of whether there is a result value or not.
val eval_test : 'a cmdlet -> bool
Evaluates a commandlet, and returns true if the exit code is 0, and false if the exit code is non-zero.

Example: This piece of code returns the file listing of "/a" if readable, or otherwise the file listing of "/b":

 
 eval (cmd_output "ls /a" |- cmd_output "ls /b")
 

Loops should be programmed with recursion, or by folding:

 eval
   (List.fold_left
     (fun acc x ->
        acc |- cmdf_output "ls %s" (Filename.quote x))
     (set_bool_code true)
     [ "/a"; "/b"; "/c" ]
   )
 


Logging



Logging outputs to "script.log" in the cwd.
val log : string -> unit
Appends the string to the log file.
val logf : ('a, unit, string, unit) Pervasives.format4 -> 'a
Same as log, but accepts a printf-like format string

The conf-*.mk files



In general, the conf-*.mk files have make syntax. However, these files should only contain name=value settings, and not more. The values should not contain any references to other variables ("${name}"), and the dollar character must be written $$.
val print_conf_file : string -> (string * string) list -> unit
Writes to file the list of variable settings
val parse_conf_file : string -> (string * string) list
Parses file

Finding libraries


type lang_env = [ `C of c_env ] 
Environment to compile and link programs for a certain language.

type c_env = {
   c_env_file : (string * string) option; (*The file this record was parsed from. The first string is the absolute file name, and the second string is the name prefix used in this file*)
   c_incdirs : string list; (*List of directories for "#include"*)
   c_libdirs : string list; (*List of library directories*)
   c_libs : string list; (*Names of libraries (w/o "lib" and suffix)*)
   c_flags : string list; (*Further flags for C compiling*)
   c_ld_flags : string list; (*Further flags for linking*)
   c_elf_rpath : bool; (*Whether c_libdirs must be added to the runtime lookup path*)
   c_config_script : string option; (*The name of a foreign config script*)
   c_godi_deps : string list; (*List of additional GODI dependencies to output*)
   c_requirements : c_env list; (*Requirements to link test programs*)
}
The environment to compile and link the mentioned libraries. The c_incdirs can be translated to further C compiler flags; the c_libdirs and c_libs can be translated to further linker flags. The c_flags and c_ld_flags are additional flags. It is also allowed to only fill c_flags and c_ld_flags and let the other components empty.

The c_config_script is the name of another script that can be called to get the C compiler and linker flags (e.g. pkg-config scripts).

The c_godi_deps are dependencies to GODI packages that are required at run-time to make the C library available. (These are usually base-foo packages. Configuration packages must not be put into this list!)

The c_requirements lists environments that are necessary to compile and link programs, but that are not merged into the regular output. For instance, many graphics libraries depend on the X11 library.

A note about shell quoting: The above lists of flags should not contain any shell metacharacters such that quoting is not necessary at all. As the flags are processed by further scripts it is expected that quoting will be taken wrong anyway, so it is the best strategy to avoid quoting.

val empty_c_env : c_env
A c_env where the lists are empty, the options are None, and the boolean fields are false.
val c_env_from_config_script : ?arg_cflags:string ->
?arg_ldflags:string ->
?args:string list -> script_name:string -> unit -> c_env
Calls the script script_name (which must be an absolute file name) and extracts the c_env from it. The C compiler flags are obtained by calling the script with argument arg_cflags, and the linker flags are obtained by calling the script with argument arg_ldflags.

The default for arg_cflags is "--cflags", and the default for arg_ldflags is "--libs". (These work in most cases.)

In args one can pass further arguments.

The function fails if the configure script cannot be called, or if it does not exit with code 0.

val create_test_whether_c_function_exists : string -> string
Input is the name of a C function. The returned string is a C program that can only be compiled and linked if the C function exists. The program returns the exit code 0.
val c_flags : ?with_requirements:bool -> c_env -> string list
Returns the collected flags to C-compile. If with_requirements=true, the flags mentioned in c_requirements are also returned (default: false).
val c_ld_flags : ?with_requirements:bool -> c_env -> string list
Returns the collected flags to link C programs. If with_requirements=true, the flags mentioned in c_requirements are also returned (default: false).
val c_compiler_name : unit -> string
Returns the command name of the C compiler
val c_compile_test : c_env -> string -> string cmdlet
The string must contain the C program to be used as test. The program is compiled and linked using the C environment. The result stored into the commandlet state is the name of the executable.
val run_test : string cmdlet
Runs the executable whose name is stored in the state. The exit code is set, and the new result is the output of the program.
val find_c_library : ?godi_deps:string list ->
?pref_incdir:string ->
?pref_libdir:string ->
?flags:string list ->
?ld_flags:string list ->
?inc_name:string ->
?requirements:c_env list ->
?locations:string list ->
?frameworks:string list ->
libs:string list ->
test:(c_env -> c_env option) ->
unit -> c_env cmdlet
Searches a C library. First, the preferred locations pref_incdir and pref_libdir are tried. The second choice are the frameworks (Mac OS X only). If this is not successful, too, searching continues with the locations found in the environment variable SEARCH_LIBS (by default, unless overriden by locations).

A C library is found if:

If found, the return value of test is the result of the commandlet.

The C environment passed to the test function is properly set up:


frameworks : If non-empty, and if the system is Mac OS X, this is a list of frameworks to try.
val parse_c_result : file:string -> prefix:string -> unit -> c_env
Parses the C environment found in file where the variables use prefix.

The syntax written by print_c_result is recognised plus a number of legacy notations.

val print_c_result : ?vars:(string * string) list ->
file:string -> prefix:string -> c_env -> unit
Prints the C environment to the file and to the screen. The prefix is prepended to the variables in file. Example: print_c_result ~file:"conf-foo.mk" ~prefix:"CONF_FOO" ce

The component c_env_file is ignored (except in c_requirements where it is output to the <prefix>_REQS variable).

The following standard variable names are used in the printed file:

The vars are appended to the file, if passed. Useful to output further non-standard variables.
val main_c_finder : ?godi_deps:string list Pervasives.ref ->
?pref_incdir:string option Pervasives.ref ->
?pref_libdir:string option Pervasives.ref ->
?c_flags:string list Pervasives.ref ->
?ld_flags:string list Pervasives.ref -> unit -> unit
A configurable main program for the case that the library is searched by find_c_library.

The arguments godi_deps, pref_incdir, pref_libdir, c_flags, and ld_flags can be set by command-line if a string reference is passed to the function.

Example:

 let pref_incdir = ref None in
 let pref_libdir = ref None in
 main_c_finder ~pref_incdir ~pref_libdir ();
 let c_opt = eval
               (find_c_library 
                  ?pref_incdir:!pref_incdir 
                  ?pref_libdir:!pref_libdir 
                  ~libs:... ~test:... ()) in
 match c_opt with
   None -> failwith "Cannot find library"
 | Some c -> print_c_result ~file:"conf-foo.mk" ~prefix:"CONF_FOO" c
 

val main_config_finder : script_basename:string -> unit -> string
A configurable main program for the case that a configure script is used (c_env_from_config_script).

In script_basename one must pass the name of the script to call, without directory, e.g. "foo-config". The script is looked up in the SEARCH_LIBS and PATH locations. A command-line parameter may be used to override the location.

The absolute path of the script is returned as string.

Whole example:

 let test ce = ... ;;
 let cmd = main_config_finder ~script_basename:"foo-config" () ;;
 let ce = c_env_from_config_script ~script_name:cmd () ;;
 match test ce with
   Some ce' ->
     print_c_result ~file:"conf-foo.mk" ~prefix:"CONF_FOO" ce'
 | None ->
     failwith "Cannot find library"