* [mkbundle] add support for baking environment variables, make endian-independent
* [runtime] Bundle support, implement missing stream processing
$ mkbundle -o hello --simple hello.exe
.fi
+.PP
+You can configure options to be passed to the Mono runtime directly
+into your executable, for this, use the
+.I --options
+flag. For example, the following disables inlining, by passing the
+"-O=-inline" command line option to the embedded executable:
+.nf
+
+ $ mkbundle -o hello --options -O=-inline --simple hello.exe
+
.PP
The simple version allows for cross-compiling, this requires a Mono
runtime to be installed in the ~/.mono/targets/TARGET/mono to be
assemblies listed on the command line option. This is useful to
distribute a self-contained image.
.TP
+.I "--env KEY=VALUE"
+Use this to hardcode an environment variable at runtime for KEY to be
+mapped to VALUE. This is useful in scenarios where you want to
+enable certain Mono runtime configuration options that are controlled
+by environment variables.
+.TP
.I "--fetch-target target"
Downloads a precompiled runtime for the specified target from the Mono
distribution site.
Places the output on `out'. If the flag -c is specified, this is the
C host program. If not, this contains the resulting executable.
.TP
+.I "--options OPTS"
+Since the resulting executable will be treated as a standalone
+program, you can use this option to pass configuration options to the
+Mono runtime and bake those into the resulting executable. These
+options are specified as
+.I OPTS.
+.Sp
+You can use the above to configure options that you would typically
+pass on the command line to Mono, before the main program is
+executed.
+.Sp
+Additionally, users of your binary can still configure their own
+options by setting the
+.I MONO_ENV_OPTIONS
+environment variable.
+.TP
.I "--target-server SERVER"
By default the mkbundle tool will download from a Mono server the
target runtimes, you can specify a different server to provide
static bool custom_mode = true;
static string embedded_options = null;
static string runtime = null;
+ static Dictionary<string,string> environment = new Dictionary<string,string>();
static string [] i18n = new string [] {
"West",
""
case "--quiet":
quiet = true;
break;
+ case "-e":
+ case "--env":
+ if (i+1 == top) {
+ Help ();
+ return 1;
+ }
+ var env = args [++i];
+ var p = env.IndexOf ('=');
+ if (p == -1)
+ environment.Add (env, "");
+ else
+ environment.Add (env.Substring (0, p), env.Substring (p+1));
+ break;
default:
sources.Add (args [i]);
break;
package.Position = package.Position + (align - (package.Position % align));
}
+ public void AddStringPair (string entry, string key, string value)
+ {
+ var kbytes = Encoding.UTF8.GetBytes (key);
+ var vbytes = Encoding.UTF8.GetBytes (value);
+
+ Console.WriteLine ("ADDING {0} to {1}", key, value);
+ if (kbytes.Length > 255){
+ Console.WriteLine ("The key value can not exceed 255 characters: " + key);
+ Environment.Exit (1);
+ }
+
+ locations [entry] = Tuple.Create (package.Position, kbytes.Length+vbytes.Length+3);
+ package.WriteByte ((byte)kbytes.Length);
+ package.Write (kbytes, 0, kbytes.Length);
+ package.WriteByte (0);
+ package.Write (vbytes, 0, vbytes.Length);
+ package.WriteByte (0);
+ package.Position = package.Position + (align - (package.Position % align));
+ }
+
public void Dump ()
{
if (quiet)
maker.Add ("config_dir:", config_dir);
if (embedded_options != null)
maker.AddString ("options:", embedded_options);
+ if (environment.Count > 0){
+ foreach (var key in environment.Keys)
+ maker.AddStringPair ("env:" + key, key, environment [key]);
+ }
maker.Dump ();
maker.Close ();
return true;
" --options OPTIONS Embed the specified Mono command line options on target\n" +
" --runtime RUNTIME Manually specifies the Mono runtime to use\n" +
" --target-server URL Specified a server to download targets from, default is " + target_server + "\n" +
+ " --env KEY=VALUE Hardcodes an environment variable for the target\n" +
"\n" +
"--custom Builds a custom launcher, options for --custom\n" +
" -c Produce stub only, do not compile\n" +
return mono_main (argc, argv);
}
-#define STREAM_INT(x) (*(uint32_t*)x)
-#define STREAM_LONG(x) (*(uint64_t*)x)
+#define STREAM_INT(x) GUINT32_TO_LE((*(uint32_t*)x))
+#define STREAM_LONG(x) GUINT64_TO_LE((*(uint64_t*)x))
+
+/**
+ * Loads a chunk of data from the file pointed to by the
+ * @fd starting at the file offset @offset for @size bytes
+ * and returns an allocated version of that string, or NULL
+ * on error.
+ */
+static char *
+load_from_region (int fd, uint64_t offset, uint64_t size)
+{
+ char *buffer;
+ off_t loc;
+ int status;
+
+ do {
+ loc = lseek (fd, offset, SEEK_SET);
+ } while (loc == -1 && errno == EINTR);
+ if (loc == -1)
+ return NULL;
+ buffer = g_malloc (size + 1);
+ if (buffer == NULL)
+ return NULL;
+ buffer [size] = 0;
+ do {
+ status = read (fd, buffer, size);
+ } while (status == -1 && errno == EINTR);
+ if (status == -1){
+ g_free (buffer);
+ return NULL;
+ }
+ return buffer;
+}
static gboolean
probe_embedded (const char *program, int *ref_argc, char **ref_argv [])
char *config = kind + strlen ("config:");
char *aname = g_strdup (config);
aname [strlen(aname)-strlen(".config")] = 0;
- mono_register_config_for_assembly (aname, config);
+ mono_register_config_for_assembly (aname, load_from_region (fd, offset, item_size));
} else if (strncmp (kind, "systemconfig:", strlen ("systemconfig:")) == 0){
- mono_config_parse_memory (kind + strlen ("systemconfig:"));
+ mono_config_parse_memory (load_from_region (fd, offset, item_size));
} else if (strncmp (kind, "options:", strlen ("options:")) == 0){
- mono_parse_options_from (kind + strlen("options:"), ref_argc, ref_argv);
+ mono_parse_options_from (load_from_region (fd, offset, item_size), ref_argc, ref_argv);
} else if (strncmp (kind, "config_dir:", strlen ("config_dir:")) == 0){
- mono_set_dirs (getenv ("MONO_PATH"), kind + strlen ("config_dir:"));
+ mono_set_dirs (getenv ("MONO_PATH"), load_from_region (fd, offset, item_size));
} else if (strncmp (kind, "machineconfig:", strlen ("machineconfig:")) == 0) {
- mono_register_machine_config (kind + strlen ("machineconfig:"));
+ mono_register_machine_config (load_from_region (fd, offset, item_size));
+ } else if (strncmp (kind, "env:", strlen ("env:")) == 0){
+ char *data = load_from_region (fd, offset, item_size);
+ uint8_t count = *data++;
+ char *value = data + count + 1;
+ g_setenv (data, value, FALSE);
} else {
fprintf (stderr, "Unknown stream on embedded package: %s\n", kind);
exit (1);