diff --git a/build-aux/build-ports.sh b/build-aux/build-ports.sh index 083e3844..13922ea0 100755 --- a/build-aux/build-ports.sh +++ b/build-aux/build-ports.sh @@ -84,8 +84,8 @@ fi get_package_dependencies_raw() {( PACKAGE_DIR=$(echo $1 | grep -Eo '^[^\.]*') ! [ -f "$SORTIX_PORTS_DIR/$PACKAGE_DIR/tixbuildinfo" ] || - grep -E "^pkg\.build-libraries=.*" "$SORTIX_PORTS_DIR/$PACKAGE_DIR/tixbuildinfo" | \ - sed 's/^pkg\.build-libraries=//' + grep -E "^(pkg\.build-libraries|pkg\.alias-of)=.*" "$SORTIX_PORTS_DIR/$PACKAGE_DIR/tixbuildinfo" | \ + sed 's/^[^=]*=//' )} # Detect the build-time dependencies for a package with missing optional @@ -151,12 +151,15 @@ strip_tix() { # Build all the packages (if needed) and otherwise install them. for PACKAGE in $PACKAGES; do if ! [ -f "$SORTIX_REPOSITORY_DIR/$PACKAGE.tix.tar.xz" ]; then + SOURCE_PACKAGE=$(grep -E "^pkg.source-package=" "$SORTIX_PORTS_DIR/$PACKAGE/tixbuildinfo" | \ + sed 's/^[^=]*=//') tix-build \ --sysroot="$SYSROOT" \ --host=$HOST \ --prefix= \ --destination="$SORTIX_REPOSITORY_DIR" \ --generation=2 \ + ${SOURCE_PACKAGE:+--source-package "$SORTIX_PORTS_DIR/$SOURCE_PACKAGE"} \ "$SORTIX_PORTS_DIR/$PACKAGE" strip_tix "$SORTIX_REPOSITORY_DIR/$PACKAGE.tix.tar.xz" fi diff --git a/share/man/man7/following-development.7 b/share/man/man7/following-development.7 index 788cb1ba..d3c9212c 100644 --- a/share/man/man7/following-development.7 +++ b/share/man/man7/following-development.7 @@ -59,6 +59,45 @@ releasing Sortix x.y, foo." to allow the maintainer to easily .Xr grep 1 for it after a release. .Sh CHANGES +.Ss Add split packages and cross-bootstrapping support to tix-build(8) +.Xr tix-build 8 +has gained a number of features that will soon be required in order to build +certain ports. In particular, it now supports the +.Sy pkg.use-bootstrap , +.Sy pkg.source-package , +and +.Sy pkg.alias-of +variables; bugs in the +.Sy pkg.subdir +variable have been fixed; and a +.Fl \-source-directory +option has been added. +.Xr tix-build 8 +must be upgraded before building ports using any of those feature. +.Bd -literal + cd /src/tix && + make clean && + make install +.Ed +.Pp +If not developing natively, set +.Ev PREFIX +to the desired location. +.Pp +If the new program isn't used, ports may fail to build due to local software not +being the exact same version +.Sy ( pkg.use-bootstrap ) , +clean or post-install in the wrong subdirectory +.Sy ( pkg.subdir) , +the +.Fl \-source-directory +option not being recognized or failing to locate the source code +.Sy ( pkg.source-package) , +stopping because +.Sy pkg.build-system +isn't set +.Sy ( pkg.alias-of) , +or other mysterious circumstances. .Ss Add German keyboard layout. The .Xr kblayout-compiler 1 diff --git a/tix/tix-build.c b/tix/tix-build.c index faf629aa..202e3705 100644 --- a/tix/tix-build.c +++ b/tix/tix-build.c @@ -39,6 +39,37 @@ #include "util.h" +struct buildvar +{ + const char* variable; + const char* value; + bool program; +}; + +static struct buildvar buildvars[] = +{ + { "AR", "ar", true }, + { "AS", "as", true }, + { "CC", "gcc", true }, + { "CFLAGS", "-Os", false }, + { "CPP", "gcc -E", true }, + { "CPP", "", false }, + { "CXXFILT", "c++filt", true }, + { "CXX", "g++", true }, + { "CXXFLAGS", "-Os", false }, + { "LD", "ld", true }, + { "LDFLAGS", "", false }, + { "NM", "nm", true }, + { "OBJCOPY", "objcopy", true }, + { "OBJDUMP", "objdump", true }, + { "PKG_CONFIG", "pkg-config", true }, + { "RANLIB", "ranlib", true }, + { "READELF", "readelf", true }, + { "STRIP", "strip", true }, +}; + +#define BUILDVARS_LENGTH (sizeof(buildvars) / sizeof(buildvars[0])) + enum build_step { BUILD_STEP_NO_SUCH_STEP, @@ -48,14 +79,14 @@ enum build_step BUILD_STEP_BUILD, BUILD_STEP_INSTALL, BUILD_STEP_POST_INSTALL, - BUILD_STEP_PACKAGE, BUILD_STEP_POST_CLEAN, + BUILD_STEP_PACKAGE, BUILD_STEP_END, }; -bool should_do_build_step(enum build_step step, - enum build_step start, - enum build_step end) +static bool should_do_build_step(enum build_step step, + enum build_step start, + enum build_step end) { return start <= step && step <= end; } @@ -63,7 +94,7 @@ bool should_do_build_step(enum build_step step, #define SHOULD_DO_BUILD_STEP(step, minfo) \ should_do_build_step((step), (minfo)->start_step, (minfo)->end_step) -enum build_step step_of_step_name(const char* step_name) +static enum build_step step_of_step_name(const char* step_name) { if ( !strcmp(step_name, "start") ) return BUILD_STEP_START; @@ -88,7 +119,7 @@ enum build_step step_of_step_name(const char* step_name) return BUILD_STEP_NO_SUCH_STEP; } -typedef struct +struct metainfo { char* build; char* build_dir; @@ -109,9 +140,11 @@ typedef struct string_array_t package_info; enum build_step start_step; enum build_step end_step; -} metainfo_t; + bool bootstrapping; + bool cross; +}; -bool has_in_path(const char* program) +static bool has_in_path(const char* program) { pid_t child_pid = fork(); if ( child_pid < 0 ) @@ -122,22 +155,24 @@ bool has_in_path(const char* program) waitpid(child_pid, &exitstatus, 0); return WIFEXITED(exitstatus) && WEXITSTATUS(exitstatus) == 0; } - close(0); open("/dev/null", O_RDONLY); - close(1); open("/dev/null", O_WRONLY); - close(2); open("/dev/null", O_WRONLY); - char* argv[] = + close(0); + close(1); + close(2); + if ( open("/dev/null", O_RDONLY) != 0 || + open("/dev/null", O_WRONLY) != 1 || + open("/dev/null", O_WRONLY) != 2 ) { - (char*) "which", - (char*) program, - (char*) NULL, - }; - execvp(argv[0], argv); + warn("/dev/null"); + _exit(1); + } + const char* argv[] = { "which", program, NULL }; + execvp(argv[0], (char**) argv); _exit(1); } -void emit_compiler_wrapper_invocation(FILE* wrapper, - metainfo_t* minfo, - const char* name) +static void emit_compiler_wrapper_invocation(FILE* wrapper, + struct metainfo* minfo, + const char* name) { fprintf(wrapper, "%s", name); if ( minfo->sysroot ) @@ -145,69 +180,19 @@ void emit_compiler_wrapper_invocation(FILE* wrapper, fprintf(wrapper, " \"$@\""); } -void emit_compiler_warning_wrapper(metainfo_t* minfo, - const char* bindir, - const char* name) -{ - if ( !minfo->sysroot ) - return; - if ( !has_in_path(name) ) - return; - const char* warnings_dir = getenv("TIX_WARNINGS_DIR"); - char* wrapper_path = print_string("%s/%s", bindir, name); - FILE* wrapper = fopen(wrapper_path, "w"); - if ( !wrapper ) - err(1, "`%s'", wrapper_path); - // TODO: Find a portable shell way of doing this. - fprintf(wrapper, "#!/bin/bash\n"); - fprint_shell_variable_assignment(wrapper, "PATH", getenv("PATH")); - fprint_shell_variable_assignment(wrapper, "TIX_WARNINGS_DIR", warnings_dir); - if ( minfo->sysroot ) - fprint_shell_variable_assignment(wrapper, "SYSROOT", minfo->sysroot); - fprintf(wrapper, "warnfile=$(mktemp --tmpdir=\"$TIX_WARNINGS_DIR\")\n"); - fprintf(wrapper, "("); - emit_compiler_wrapper_invocation(wrapper, minfo, name); - fprintf(wrapper, ") 2> >(tee $warnfile >&2)\n"); - fprintf(wrapper, "exitstatus=$?\n"); - fprintf(wrapper, "if test -s \"$warnfile\"; then\n"); - fprintf(wrapper, " if test $exitstatus = 0; then\n"); - fprintf(wrapper, " (echo \"cd $(pwd) && "); - emit_compiler_wrapper_invocation(wrapper, minfo, name); - fprintf(wrapper, " && cat \"$warnfile\") > \"$warnfile.warn\"\n"); - fprintf(wrapper, " else\n"); - fprintf(wrapper, " (echo \"cd $(pwd) && "); - emit_compiler_wrapper_invocation(wrapper, minfo, name); - fprintf(wrapper, " && cat \"$warnfile\") > \"$warnfile.err\"\n"); - fprintf(wrapper, " fi\n"); - fprintf(wrapper, "fi\n"); - fprintf(wrapper, "rm -f \"$warnfile\"\n"); - fprintf(wrapper, "exit $exitstatus\n"); - fflush(wrapper); - fchmod_plus_x(fileno(wrapper)); - fclose(wrapper); - - free(wrapper_path); -} - -void emit_compiler_warning_cross_wrapper(metainfo_t* minfo, - const char* bindir, - const char* name) -{ - char* cross_name = print_string("%s-%s", minfo->host, name); - emit_compiler_warning_wrapper(minfo, bindir, cross_name); - free(cross_name); -} - -void emit_compiler_sysroot_wrapper(metainfo_t* minfo, - const char* bindir, - const char* name) +static void emit_compiler_sysroot_wrapper(struct metainfo* minfo, + const char* bindir, + const char* name) { if ( !has_in_path(name) ) return; - char* wrapper_path = print_string("%s/%s", bindir, name); + char* wrapper_path = join_paths(bindir, name); + if ( !wrapper_path ) + err(1, "malloc"); FILE* wrapper = fopen(wrapper_path, "w"); if ( !wrapper ) err(1, "`%s'", wrapper_path); + fprintf(wrapper, "#!/bin/sh\n"); fprint_shell_variable_assignment(wrapper, "PATH", getenv("PATH")); if ( minfo->sysroot ) fprint_shell_variable_assignment(wrapper, "SYSROOT", minfo->sysroot); @@ -216,135 +201,169 @@ void emit_compiler_sysroot_wrapper(metainfo_t* minfo, fprintf(wrapper, "\n"); fflush(wrapper); fchmod_plus_x(fileno(wrapper)); + if ( ferror(wrapper) || fflush(wrapper) == EOF ) + err(1, "%s", wrapper_path); fclose(wrapper); - free(wrapper_path); } -void emit_compiler_sysroot_cross_wrapper(metainfo_t* minfo, - const char* bindir, - const char* name) +static void emit_compiler_sysroot_cross_wrapper(struct metainfo* minfo, + const char* bindir, + const char* name) { char* cross_name = print_string("%s-%s", minfo->host, name); + if ( !cross_name ) + err(1, "malloc"); emit_compiler_sysroot_wrapper(minfo, bindir, cross_name); free(cross_name); } -void emit_pkg_config_wrapper(metainfo_t* minfo) +static void emit_pkg_config_wrapper(struct metainfo* minfo, const char* bindir) { - char* bindir = print_string("%s/bin", tmp_root); - if ( mkdir(bindir, 0777) < 0 ) - err(1, "mkdir: %s", bindir); - // Create a pkg-config script for the build system. - char* pkg_config_for_build_path = print_string("%s/build-pkg-config", bindir); + char* pkg_config_for_build_path = join_paths(bindir, "pkg-config"); + if ( !pkg_config_for_build_path ) + err(1, "malloc"); FILE* pkg_config_for_build = fopen(pkg_config_for_build_path, "w"); if ( !pkg_config_for_build ) err(1, "`%s'", pkg_config_for_build_path); fprintf(pkg_config_for_build, "#!/bin/sh\n"); - fprint_shell_variable_assignment(pkg_config_for_build, "PATH", getenv("PATH")); - fprint_shell_variable_assignment(pkg_config_for_build, "PKG_CONFIG", getenv("PKG_CONFIG")); - fprint_shell_variable_assignment(pkg_config_for_build, "PKG_CONFIG_PATH", getenv("PKG_CONFIG_PATH")); - fprint_shell_variable_assignment(pkg_config_for_build, "PKG_CONFIG_SYSROOT_DIR", getenv("PKG_CONFIG_SYSROOT_DIR")); - fprint_shell_variable_assignment(pkg_config_for_build, "PKG_CONFIG_FOR_BUILD", getenv("PKG_CONFIG_FOR_BUILD")); - fprint_shell_variable_assignment(pkg_config_for_build, "PKG_CONFIG_LIBDIR", getenv("PKG_CONFIG_LIBDIR")); - fprintf(pkg_config_for_build, "exec ${PKG_CONFIG:-pkg-config} \"$@\"\n"); - fflush(pkg_config_for_build); + fprint_shell_variable_assignment(pkg_config_for_build, + "PATH", getenv("PATH")); + fprint_shell_variable_assignment(pkg_config_for_build, + "PKG_CONFIG", getenv("PKG_CONFIG")); + fprint_shell_variable_assignment(pkg_config_for_build, + "PKG_CONFIG_FOR_BUILD", getenv("PKG_CONFIG_FOR_BUILD")); + if ( getenv("PKG_CONFIG_PATH_FOR_BUILD") ) + fprint_shell_variable_assignment(pkg_config_for_build, + "PKG_CONFIG_PATH", getenv("PKG_CONFIG_PATH_FOR_BUILD")); + else + fprint_shell_variable_assignment(pkg_config_for_build, + "PKG_CONFIG_PATH", getenv("PKG_CONFIG_PATH")); + if ( getenv("PKG_CONFIG_SYSROOT_DIR_FOR_BUILD") ) + fprint_shell_variable_assignment(pkg_config_for_build, + "PKG_CONFIG_SYSROOT_DIR", + getenv("PKG_CONFIG_SYSROOT_DIR_FOR_BUILD")); + else + fprint_shell_variable_assignment(pkg_config_for_build, + "PKG_CONFIG_SYSROOT_DIR", getenv("PKG_CONFIG_SYSROOT_DIR")); + if ( getenv("PKG_CONFIG_LIBDIR_FOR_BUILD") ) + fprint_shell_variable_assignment(pkg_config_for_build, + "PKG_CONFIG_LIBDIR", getenv("PKG_CONFIG_LIBDIR_FOR_BUILD")); + else + fprint_shell_variable_assignment(pkg_config_for_build, + "PKG_CONFIG_LIBDIR", getenv("PKG_CONFIG_LIBDIR")); + fprintf(pkg_config_for_build, + "exec ${PKG_CONFIG_FOR_BUILD:-${PKG_CONFIG:-pkg-config}} \"$@\"\n"); + if ( ferror(pkg_config_for_build) || fflush(pkg_config_for_build) == EOF ) + err(1, "%s", pkg_config_for_build_path); fchmod_plus_x(fileno(pkg_config_for_build)); fclose(pkg_config_for_build); free(pkg_config_for_build_path); // Create a pkg-config script for the host system. - char* pkg_config_path = print_string("%s/pkg-config", bindir); + char* var_pkg_config_libdir = + print_string("%s%s/lib/pkgconfig", + minfo->sysroot, minfo->exec_prefix); + if ( !var_pkg_config_libdir ) + err(1, "malloc"); + char* var_pkg_config_path = strdup(var_pkg_config_libdir); + if ( !var_pkg_config_path ) + err(1, "malloc"); + char* var_pkg_config_sysroot_dir = strdup(minfo->sysroot); + if ( !var_pkg_config_sysroot_dir ) + err(1, "malloc"); + char* pkg_config_name = print_string("%s-pkg-config", minfo->host); + if ( !pkg_config_name ) + err(1, "malloc"); + char* pkg_config_path = join_paths(bindir, pkg_config_name); + if ( !pkg_config_path ) + err(1, "malloc"); FILE* pkg_config = fopen(pkg_config_path, "w"); if ( !pkg_config ) err(1, "`%s'", pkg_config_path); fprintf(pkg_config, "#!/bin/sh\n"); fprint_shell_variable_assignment(pkg_config, "PATH", getenv("PATH")); - fprint_shell_variable_assignment(pkg_config, "PKG_CONFIG", getenv("PKG_CONFIG")); - fprintf(pkg_config, "exec ${PKG_CONFIG:-pkg-config} --static \"$@\"\n"); + fprint_shell_variable_assignment(pkg_config, + "PKG_CONFIG", getenv("PKG_CONFIG")); + fprint_shell_variable_assignment(pkg_config, + "PKG_CONFIG_PATH", var_pkg_config_path); + fprint_shell_variable_assignment(pkg_config, + "PKG_CONFIG_SYSROOT_DIR", var_pkg_config_sysroot_dir); + fprint_shell_variable_assignment(pkg_config, + "PKG_CONFIG_LIBDIR", var_pkg_config_libdir); + // Pass --static as Sortix only static links at the moment. + fprintf(pkg_config, "exec ${PKG_CONFIG:-%s} --static \"$@\"\n", + has_in_path(pkg_config_name) ? pkg_config_name : "pkg-config"); fflush(pkg_config); + if ( ferror(pkg_config) || fflush(pkg_config) == EOF ) + err(1, "%s", pkg_config_path); fchmod_plus_x(fileno(pkg_config)); fclose(pkg_config); free(pkg_config_path); - - // Point to the correct pkg-config configuration through the environment. - char* var_pkg_config = print_string("%s/pkg-config", bindir); - char* var_pkg_config_for_build = print_string("%s/build-pkg-config", bindir); - char* var_pkg_config_libdir = - print_string("%s%s/lib/pkgconfig", - minfo->sysroot, minfo->exec_prefix); - char* var_pkg_config_path = print_string("%s", var_pkg_config_libdir); - char* var_pkg_config_sysroot_dir = print_string("%s", minfo->sysroot); - setenv("PKG_CONFIG", var_pkg_config, 1); - setenv("PKG_CONFIG_FOR_BUILD", var_pkg_config_for_build, 1); - setenv("PKG_CONFIG_LIBDIR", var_pkg_config_libdir, 1); - setenv("PKG_CONFIG_PATH", var_pkg_config_path, 1); - setenv("PKG_CONFIG_SYSROOT_DIR", var_pkg_config_sysroot_dir, 1); - free(var_pkg_config); - free(var_pkg_config_for_build); free(var_pkg_config_libdir); free(var_pkg_config_path); free(var_pkg_config_sysroot_dir); +} - if ( getenv("TIX_WARNINGS_DIR") ) +static void append_to_path(const char* directory) +{ + const char* path = getenv("PATH"); + if ( path && path[0] ) { - char* warnings_dir = print_string("%s/%s", getenv("TIX_WARNINGS_DIR"), minfo->package_name); - if ( mkdir(warnings_dir, 0755) == 0 || errno == EEXIST ) - { - setenv("TIX_WARNINGS_DIR", warnings_dir, 1); - } - else - { - err(1, "mkdir: `%s': compiler warnings won't be saved", warnings_dir); - unsetenv("TIX_WARNINGS_DIR"); - } - free(warnings_dir); + char* new_path = print_string("%s:%s", directory, path); + if ( !new_path ) + err(1, "malloc"); + if ( setenv("PATH", new_path, 1) < 0 ) + err(1, "setenv"); + free(new_path); } + else if ( setenv("PATH", directory, 1) < 0 ) + err(1, "setenv"); +} +static void EmitWrappers(struct metainfo* minfo) +{ + if ( !minfo->cross ) + return; + + char* bindir = join_paths(tmp_root, "bin"); + if ( mkdir(bindir, 0777) < 0 ) + err(1, "mkdir: %s", bindir); + + emit_pkg_config_wrapper(minfo, bindir); emit_compiler_sysroot_cross_wrapper(minfo, bindir, "cc"); emit_compiler_sysroot_cross_wrapper(minfo, bindir, "gcc"); emit_compiler_sysroot_cross_wrapper(minfo, bindir, "c++"); emit_compiler_sysroot_cross_wrapper(minfo, bindir, "g++"); emit_compiler_sysroot_cross_wrapper(minfo, bindir, "ld"); - if ( getenv("TIX_WARNINGS_DIR") ) - { - emit_compiler_warning_wrapper(minfo, bindir, "cc"); - emit_compiler_warning_wrapper(minfo, bindir, "gcc"); - emit_compiler_warning_wrapper(minfo, bindir, "c++"); - emit_compiler_warning_wrapper(minfo, bindir, "g++"); - - emit_compiler_warning_cross_wrapper(minfo, bindir, "cc"); - emit_compiler_warning_cross_wrapper(minfo, bindir, "gcc"); - emit_compiler_warning_cross_wrapper(minfo, bindir, "c++"); - emit_compiler_warning_cross_wrapper(minfo, bindir, "g++"); - } - - char* new_path = print_string("%s:%s", bindir, getenv("PATH") ? getenv("PATH") : ""); - setenv("PATH", new_path, 1); - free(new_path); + append_to_path(bindir); free(bindir); } -void SetNeedVariableBuildTool(metainfo_t* minfo, - const char* variable, - const char* value) +static void SetNeedVariableBuildTool(struct metainfo* minfo, + const char* variable, + const char* value) { string_array_t* pkg_info = &minfo->package_info; - const char* needed_vars = dictionary_get_def(pkg_info, "pkg.make.needed-vars", "true"); + const char* needed_vars = + dictionary_get_def(pkg_info, "pkg.make.needed-vars", "true"); char* key = print_string("pkg.make.needed-vars.%s", variable); + if ( !key ) + err(1, "malloc"); const char* needed_var = dictionary_get_def(pkg_info, key, needed_vars); free(key); if ( !parse_boolean(needed_var) ) return; - setenv(variable, value, 1); + if ( setenv(variable, value, 1) < 0 ) + err(1, "setenv"); } -void SetNeedVariableCrossTool(metainfo_t* minfo, - const char* variable, - const char* value) +static void SetNeedVariableCrossTool(struct metainfo* minfo, + const char* variable, + const char* value) { if ( strcmp(minfo->build, minfo->host) == 0 ) { @@ -353,140 +372,150 @@ void SetNeedVariableCrossTool(metainfo_t* minfo, else { char* newvalue = print_string("%s-%s", minfo->host, value); + if ( !newvalue ) + err(1, "malloc"); SetNeedVariableBuildTool(minfo, variable, newvalue); free(newvalue); } } -void SetNeededVariables(metainfo_t* minfo) +static void SetNeededVariables(struct metainfo* minfo) { - SetNeedVariableBuildTool(minfo, "AR_FOR_BUILD", "ar"); - SetNeedVariableBuildTool(minfo, "AS_FOR_BUILD", "as"); - SetNeedVariableBuildTool(minfo, "CC_FOR_BUILD", "gcc"); - SetNeedVariableBuildTool(minfo, "CPP_FOR_BUILD", "gcc -E"); - SetNeedVariableBuildTool(minfo, "CXXFILT_FOR_BUILD", "c++filt"); - SetNeedVariableBuildTool(minfo, "CXX_FOR_BUILD", "g++"); - SetNeedVariableBuildTool(minfo, "LD_FOR_BUILD", "ld"); - SetNeedVariableBuildTool(minfo, "NM_FOR_BUILD", "nm"); - SetNeedVariableBuildTool(minfo, "OBJCOPY_FOR_BUILD", "objcopy"); - SetNeedVariableBuildTool(minfo, "OBJDUMP_FOR_BUILD", "objdump"); - SetNeedVariableBuildTool(minfo, "RANLIB_FOR_BUILD", "ranlib"); - SetNeedVariableBuildTool(minfo, "READELF_FOR_BUILD", "readelf"); - SetNeedVariableBuildTool(minfo, "STRIP_FOR_BUILD", "strip"); - - SetNeedVariableCrossTool(minfo, "AR", "ar"); - SetNeedVariableCrossTool(minfo, "AS", "as"); - SetNeedVariableCrossTool(minfo, "CC", "gcc"); - SetNeedVariableCrossTool(minfo, "CPP", "gcc -E"); - SetNeedVariableCrossTool(minfo, "CXXFILT", "c++filt"); - SetNeedVariableCrossTool(minfo, "CXX", "g++"); - SetNeedVariableCrossTool(minfo, "LD", "ld"); - SetNeedVariableCrossTool(minfo, "NM", "nm"); - SetNeedVariableCrossTool(minfo, "OBJCOPY", "objcopy"); - SetNeedVariableCrossTool(minfo, "OBJDUMP", "objdump"); - SetNeedVariableCrossTool(minfo, "RANLIB", "ranlib"); - SetNeedVariableCrossTool(minfo, "READELF", "readelf"); - SetNeedVariableCrossTool(minfo, "STRIP", "strip"); -} - -void Configure(metainfo_t* minfo, const char* subdir) -{ - if ( fork_and_wait_or_recovery() ) + if ( minfo->bootstrapping ) { - string_array_t* pkg_info = &minfo->package_info; - const char* configure_raw = - dictionary_get_def(pkg_info, "pkg.configure.cmd", "./configure"); - char* configure; - if ( strcmp(minfo->build_dir, minfo->package_dir) == 0 ) - configure = strdup(configure_raw); - else - configure = print_string("%s/%s", minfo->package_dir, configure_raw); - const char* conf_extra_args = - dictionary_get_def(pkg_info, "pkg.configure.args", ""); - const char* conf_extra_vars = - dictionary_get_def(pkg_info, "pkg.configure.vars", ""); - bool with_sysroot = - parse_boolean(dictionary_get_def(pkg_info, "pkg.configure.with-sysroot", - "false")); - // TODO: I am unclear if this issue still affects gcc, I might have - // forgotten to set pkg.configure.with-sysroot-ld-bug=true there. - const char* with_sysroot_ld_bug_default = "false"; - if ( !strcmp(minfo->package_name, "gcc") ) - with_sysroot_ld_bug_default = "true"; - bool with_sysroot_ld_bug = - parse_boolean(dictionary_get_def(pkg_info, "pkg.configure.with-sysroot-ld-bug", - with_sysroot_ld_bug_default )); - bool with_build_sysroot = - parse_boolean(dictionary_get_def(pkg_info, "pkg.configure.with-build-sysroot", - "false")); - if ( chdir(minfo->build_dir) != 0 ) - err(1, "chdir: `%s'", minfo->build_dir); - if ( subdir && chdir(subdir) != 0 ) - err(1, "chdir: `%s/%s'", minfo->build_dir, subdir); - SetNeededVariables(minfo); - string_array_t env_vars = string_array_make(); - string_array_append_token_string(&env_vars, conf_extra_vars); - for ( size_t i = 0; i < env_vars.length; i++ ) + for ( size_t i = 0; i < BUILDVARS_LENGTH; i++ ) + unsetenv(buildvars[i].variable); + for ( size_t i = 0; i < BUILDVARS_LENGTH; i++ ) { - char* key = env_vars.strings[i]; - assert(key); - char* assignment = strchr((char*) key, '='); - if ( !assignment ) - { - if ( !strncmp(key, "unset ", strlen("unset ")) ) - unsetenv(key + strlen("unset ")); - continue; - } - *assignment = '\0'; - char* value = assignment+1; - setenv(key, value, 1); + char* for_build = + print_string("%s_FOR_BUILD", buildvars[i].variable); + if ( !for_build ) + err(1, "malloc"); + const char* value = getenv(for_build); + if ( value && setenv(buildvars[i].variable, value, 1) < 0 ) + err(1, "setenv"); + free(for_build); } - const char* fixed_cmd_argv[] = - { - configure, - print_string("--build=%s", minfo->build), - print_string("--host=%s", minfo->host), - print_string("--target=%s", minfo->target), - print_string("--prefix=%s", minfo->prefix), - print_string("--exec-prefix=%s", minfo->exec_prefix), - NULL - }; - string_array_t args = string_array_make(); - for ( size_t i = 0; fixed_cmd_argv[i]; i++ ) - string_array_append(&args, fixed_cmd_argv[i]); - if ( minfo->sysroot && with_build_sysroot ) - { - string_array_append(&args, print_string("--with-build-sysroot=%s", - minfo->sysroot)); - if ( minfo->sysroot && with_sysroot ) - { - // TODO: Binutils has a bug where the empty string means that - // sysroot support is disabled and ld --sysroot won't work - // so set it to / here for compatibility. - // TODO: GCC has a bug where it doesn't use the - // --with-build-sysroot value when --with-sysroot= when - // locating standard library headers. - if ( with_sysroot_ld_bug ) - string_array_append(&args, "--with-sysroot=/"); - else - string_array_append(&args, "--with-sysroot="); - } - } - else if ( minfo->sysroot && with_sysroot ) - { - string_array_append(&args, print_string("--with-sysroot=%s", - minfo->sysroot)); - } - string_array_append_token_string(&args, conf_extra_args); - string_array_append(&args, NULL); - recovery_execvp(args.strings[0], (char* const*) args.strings); - err(127, "`%s'", args.strings[0]); + return; } + + for ( size_t i = 0; i < BUILDVARS_LENGTH; i++ ) + { + if ( !buildvars[i].program && !getenv(buildvars[i].variable) ) + continue; + char* for_build = print_string("%s_FOR_BUILD", buildvars[i].variable); + if ( !for_build ) + err(1, "malloc"); + SetNeedVariableBuildTool(minfo, for_build, buildvars[i].value); + free(for_build); + } + for ( size_t i = 0; i < BUILDVARS_LENGTH; i++ ) + if ( buildvars[i].program ) + SetNeedVariableCrossTool(minfo, buildvars[i].variable, + buildvars[i].value); } -bool TestDirty(metainfo_t* minfo, - const char* subdir, - const char* candidate) +static void Configure(struct metainfo* minfo) +{ + if ( !fork_and_wait_or_recovery() ) + return; + string_array_t* pkg_info = &minfo->package_info; + const char* subdir = dictionary_get(pkg_info, "pkg.subdir"); + const char* configure_raw = + dictionary_get_def(pkg_info, "pkg.configure.cmd", "./configure"); + char* configure; + if ( strcmp(minfo->build_dir, minfo->package_dir) == 0 ) + configure = strdup(configure_raw); + else + configure = join_paths(minfo->package_dir, configure_raw); + if ( !configure ) + err(1, "malloc"); + const char* conf_extra_args = + dictionary_get_def(pkg_info, "pkg.configure.args", ""); + const char* conf_extra_vars = + dictionary_get_def(pkg_info, "pkg.configure.vars", ""); + bool with_sysroot = + parse_boolean(dictionary_get_def(pkg_info, + "pkg.configure.with-sysroot", "false")); + // TODO: I am unclear if this issue still affects gcc, I might have + // forgotten to set pkg.configure.with-sysroot-ld-bug=true there. + const char* with_sysroot_ld_bug_default = "false"; + if ( !strcmp(minfo->package_name, "gcc") ) + with_sysroot_ld_bug_default = "true"; + bool with_sysroot_ld_bug = + parse_boolean(dictionary_get_def(pkg_info, + "pkg.configure.with-sysroot-ld-bug", with_sysroot_ld_bug_default )); + bool with_build_sysroot = + parse_boolean(dictionary_get_def(pkg_info, + "pkg.configure.with-build-sysroot", "false")); + if ( chdir(minfo->build_dir) != 0 ) + err(1, "chdir: `%s'", minfo->build_dir); + if ( subdir && chdir(subdir) != 0 ) + err(1, "chdir: `%s/%s'", minfo->build_dir, subdir); + SetNeededVariables(minfo); + string_array_t env_vars = string_array_make(); + string_array_append_token_string(&env_vars, conf_extra_vars); + for ( size_t i = 0; i < env_vars.length; i++ ) + { + char* key = env_vars.strings[i]; + assert(key); + char* assignment = strchr((char*) key, '='); + if ( !assignment ) + { + if ( !strncmp(key, "unset ", strlen("unset ")) ) + unsetenv(key + strlen("unset ")); + continue; + } + *assignment = '\0'; + char* value = assignment+1; + setenv(key, value, 1); + } + const char* fixed_cmd_argv[] = + { + configure, + print_string("--prefix=%s", minfo->prefix), + print_string("--exec-prefix=%s", minfo->exec_prefix), + print_string("--build=%s", minfo->build), + minfo->bootstrapping ? NULL : + print_string("--host=%s", minfo->host), + print_string("--target=%s", minfo->target), + NULL + }; + string_array_t args = string_array_make(); + for ( size_t i = 0; fixed_cmd_argv[i]; i++ ) + string_array_append(&args, fixed_cmd_argv[i]); + if ( minfo->sysroot && with_build_sysroot ) + { + string_array_append(&args, print_string("--with-build-sysroot=%s", + minfo->sysroot)); + if ( minfo->sysroot && with_sysroot ) + { + // TODO: Binutils has a bug where the empty string means that + // sysroot support is disabled and ld --sysroot won't work + // so set it to / here for compatibility. + // TODO: GCC has a bug where it doesn't use the + // --with-build-sysroot value when --with-sysroot= when + // locating standard library headers. + if ( with_sysroot_ld_bug ) + string_array_append(&args, "--with-sysroot=/"); + else + string_array_append(&args, "--with-sysroot="); + } + } + else if ( minfo->sysroot && with_sysroot ) + { + string_array_append(&args, print_string("--with-sysroot=%s", + minfo->sysroot)); + } + string_array_append_token_string(&args, conf_extra_args); + string_array_append(&args, NULL); + recovery_execvp(args.strings[0], (char* const*) args.strings); + err(127, "`%s'", args.strings[0]); +} + +static bool TestDirty(struct metainfo* minfo, + const char* subdir, + const char* candidate) { if ( !subdir ) subdir = "."; @@ -498,10 +527,11 @@ bool TestDirty(metainfo_t* minfo, return result; } -bool IsDirty(metainfo_t* minfo, const char* subdir) +static bool IsDirty(struct metainfo* minfo) { string_array_t* pkg_info = &minfo->package_info; const char* dirty_file = dictionary_get(pkg_info, "pkg.dirty-file"); + const char* subdir = dictionary_get(pkg_info, "pkg.subdir"); if ( dirty_file ) return TestDirty(minfo, subdir, dirty_file); return TestDirty(minfo, subdir, "config.log") || @@ -509,87 +539,282 @@ bool IsDirty(metainfo_t* minfo, const char* subdir) TestDirty(minfo, subdir, "makefile"); } -void Make(metainfo_t* minfo, const char* make_target, const char* destdir, - bool die_on_error, const char* subdir) +static void Make(struct metainfo* minfo, + const char* make_target, + const char* destdir, + bool die_on_error, + const char* subdir) { - if ( (!die_on_error && fork_and_wait_or_death_def(die_on_error)) || - (die_on_error && fork_and_wait_or_recovery()) ) + if ( !(die_on_error ? + fork_and_wait_or_recovery() : + fork_and_wait_or_death_def(false)) ) + return; + + string_array_t* pkg_info = &minfo->package_info; + char* make = strdup(minfo->make); + const char* override_make = dictionary_get(pkg_info, "pkg.make.cmd"); + const char* make_extra_args = + dictionary_get_def(pkg_info, "pkg.make.args", ""); + const char* make_extra_vars = + dictionary_get_def(pkg_info, "pkg.make.vars", ""); + if ( override_make ) { - string_array_t* pkg_info = &minfo->package_info; - char* make = strdup(minfo->make); - const char* override_make = dictionary_get(pkg_info, "pkg.make.cmd"); - const char* make_extra_args = dictionary_get_def(pkg_info, "pkg.make.args", ""); - const char* make_extra_vars = dictionary_get_def(pkg_info, "pkg.make.vars", ""); - if ( override_make ) - { - free(make); - make = join_paths(minfo->package_dir, override_make); - } - SetNeededVariables(minfo); - if ( chdir(minfo->build_dir) != 0 ) - err(1, "chdir: `%s'", minfo->build_dir); - if ( subdir && chdir(subdir) != 0 ) - err(1, "chdir: `%s/%s'", minfo->build_dir, subdir); - if ( destdir ) - setenv("DESTDIR", destdir, 1); - setenv("BUILD", minfo->build, 1); - setenv("HOST", minfo->host, 1); - setenv("TARGET", minfo->target, 1); - if ( minfo->prefix ) - setenv("PREFIX", minfo->prefix, 1); - else - unsetenv("PREFIX"); - if ( minfo->exec_prefix ) - setenv("EXEC_PREFIX", minfo->exec_prefix, 1); - else - unsetenv("EXEC_PREFIX"); - if ( minfo->makeflags ) - setenv("MAKEFLAGS", minfo->makeflags, 1); - setenv("MAKE", minfo->make, 1); - string_array_t env_vars = string_array_make(); - string_array_append_token_string(&env_vars, make_extra_vars); - for ( size_t i = 0; i < env_vars.length; i++ ) - { - char* key = env_vars.strings[i]; - assert(key); - char* assignment = strchr((char*) key, '='); - if ( !assignment ) - { - if ( !strncmp(key, "unset ", strlen("unset ")) ) - unsetenv(key + strlen("unset ")); - continue; - } - *assignment = '\0'; - char* value = assignment+1; - setenv(key, value, 1); - } - const char* fixed_cmd_argv[] = - { - make, - NULL - }; - string_array_t args = string_array_make(); - for ( size_t i = 0; fixed_cmd_argv[i]; i++ ) - string_array_append(&args, fixed_cmd_argv[i]); - string_array_append_token_string(&args, make_target); - string_array_append_token_string(&args, make_extra_args); - if ( !die_on_error ) - string_array_append(&args, "-k"); - string_array_append(&args, NULL); - if ( die_on_error ) - recovery_execvp(args.strings[0], (char* const*) args.strings); - else - execvp(args.strings[0], (char* const*) args.strings); - err(127, "`%s'", args.strings[0]); + free(make); + make = join_paths(minfo->package_dir, override_make); } + SetNeededVariables(minfo); + if ( chdir(minfo->build_dir) != 0 ) + err(1, "chdir: `%s'", minfo->build_dir); + if ( subdir && chdir(subdir) != 0 ) + err(1, "chdir: `%s/%s'", minfo->build_dir, subdir); + if ( !minfo->bootstrapping && destdir ) + setenv("DESTDIR", destdir, 1); + setenv("BUILD", minfo->build, 1); + setenv("HOST", minfo->host, 1); + setenv("TARGET", minfo->target, 1); + if ( minfo->prefix ) + setenv("PREFIX", minfo->prefix, 1); + else + unsetenv("PREFIX"); + if ( minfo->exec_prefix ) + setenv("EXEC_PREFIX", minfo->exec_prefix, 1); + else + unsetenv("EXEC_PREFIX"); + if ( minfo->makeflags ) + setenv("MAKEFLAGS", minfo->makeflags, 1); + setenv("MAKE", minfo->make, 1); + string_array_t env_vars = string_array_make(); + string_array_append_token_string(&env_vars, make_extra_vars); + for ( size_t i = 0; i < env_vars.length; i++ ) + { + char* key = env_vars.strings[i]; + assert(key); + char* assignment = strchr((char*) key, '='); + if ( !assignment ) + { + if ( !strncmp(key, "unset ", strlen("unset ")) ) + unsetenv(key + strlen("unset ")); + continue; + } + *assignment = '\0'; + char* value = assignment+1; + setenv(key, value, 1); + } + const char* fixed_cmd_argv[] = { make, NULL }; + string_array_t args = string_array_make(); + for ( size_t i = 0; fixed_cmd_argv[i]; i++ ) + string_array_append(&args, fixed_cmd_argv[i]); + string_array_append_token_string(&args, make_target); + string_array_append_token_string(&args, make_extra_args); + if ( !die_on_error ) + string_array_append(&args, "-k"); + string_array_append(&args, NULL); + if ( die_on_error ) + recovery_execvp(args.strings[0], (char* const*) args.strings); + else + execvp(args.strings[0], (char* const*) args.strings); + err(127, "`%s'", args.strings[0]); } -void BuildPackage(metainfo_t* minfo) +static void Clean(struct metainfo* minfo) { - // Detect which build system we are interfacing with. string_array_t* pinfo = &minfo->package_info; + const char* subdir = dictionary_get(pinfo, "pkg.subdir"); + const char* build_system = + dictionary_get_def(pinfo, "pkg.build-system", "none"); + const char* default_clean_target = + !strcmp(build_system, "configure") ? "distclean" : "clean"; + const char* clean_target = + dictionary_get_def(pinfo, "pkg.make.clean-target", + default_clean_target); + const char* ignore_clean_failure_var = + dictionary_get_def(pinfo, "pkg.make.ignore-clean-failure", "true"); + bool ignore_clean_failure = parse_boolean(ignore_clean_failure_var); + + Make(minfo, clean_target, NULL, !ignore_clean_failure, subdir); +} + +static void Build(struct metainfo* minfo) +{ + string_array_t* pinfo = &minfo->package_info; + const char* subdir = dictionary_get(pinfo, "pkg.subdir"); + const char* build_target = + dictionary_get_def(pinfo, "pkg.make.build-target", "all"); + + Make(minfo, build_target, NULL, true, subdir); +} + +static void CreateDestination(void) +{ + char* tardir_rel = join_paths(tmp_root, "tix"); + char* destdir_rel = join_paths(tardir_rel, "data"); + char* tixdir_rel = join_paths(tardir_rel, "tix"); + + if ( mkdir(tardir_rel, 0777) < 0 ) + err(1, "mkdir: %s", tardir_rel); + if ( mkdir(destdir_rel, 0755) != 0 ) + err(1, "mkdir: `%s'", destdir_rel); + if ( mkdir(tixdir_rel, 0755) != 0 ) + err(1, "mkdir: `%s'", tixdir_rel); + + free(tardir_rel); + free(destdir_rel); + free(tixdir_rel); +} + +static void Install(struct metainfo* minfo) +{ + string_array_t* pinfo = &minfo->package_info; + const char* subdir = dictionary_get(pinfo, "pkg.subdir"); + const char* install_target = + dictionary_get_def(pinfo, "pkg.make.install-target", "install"); + char* tardir_rel = join_paths(tmp_root, "tix"); + char* destdir_rel = join_paths(tardir_rel, "data"); + char* destdir = realpath(destdir_rel, NULL); + if ( !destdir ) + err(1, "realpath: %s", destdir_rel); + + Make(minfo, install_target, destdir, true, subdir); + + free(tardir_rel); + free(destdir_rel); + free(destdir); +} + +static void PostInstall(struct metainfo* minfo) +{ + string_array_t* pinfo = &minfo->package_info; + const char* post_install_cmd = + dictionary_get(pinfo, "pkg.post-install.cmd"); + if ( !post_install_cmd ) + return; + + if ( !fork_and_wait_or_recovery() ) + return; + + const char* subdir = dictionary_get(pinfo, "pkg.subdir"); + char* tardir_rel = join_paths(tmp_root, "tix"); + char* destdir_rel = join_paths(tardir_rel, "data"); + char* destdir = realpath(destdir_rel, NULL); + if ( !destdir ) + err(1, "realpath: %s", destdir_rel); + + SetNeededVariables(minfo); + if ( chdir(minfo->package_dir) != 0 ) + err(1, "chdir: `%s'", minfo->package_dir); + if ( subdir && chdir(subdir) != 0 ) + err(1, "chdir: `%s/%s'", minfo->build_dir, subdir); + setenv("TIX_BUILD_DIR", minfo->build_dir, 1); + setenv("TIX_SOURCE_DIR", minfo->package_dir, 1); + setenv("TIX_INSTALL_DIR", destdir, 1); + if ( minfo->sysroot ) + setenv("TIX_SYSROOT", minfo->sysroot, 1); + else + unsetenv("TIX_SYSROOT"); + setenv("BUILD", minfo->build, 1); + setenv("HOST", minfo->host, 1); + setenv("TARGET", minfo->target, 1); + if ( minfo->prefix ) + setenv("PREFIX", minfo->prefix, 1); + else + unsetenv("PREFIX"); + if ( minfo->exec_prefix ) + setenv("EXEC_PREFIX", minfo->exec_prefix, 1); + else + unsetenv("EXEC_PREFIX"); + const char* cmd_argv[] = + { + post_install_cmd, + NULL + }; + recovery_execvp(cmd_argv[0], (char* const*) cmd_argv); + err(127, "%s", cmd_argv[0]); +} + +static void TixInfo(struct metainfo* minfo) +{ + string_array_t* pinfo = &minfo->package_info; + char* tardir_rel = join_paths(tmp_root, "tix"); + if ( !tardir_rel ) + err(1, "malloc"); + char* tixinfo_rel = join_paths(tardir_rel, "tix/tixinfo"); + if ( !tixinfo_rel ) + err(1, "malloc"); + const char* alias = dictionary_get(pinfo, "pkg.alias-of"); + const char* runtime_deps = dictionary_get(pinfo, "pkg.runtime-deps"); + bool location_independent = + parse_boolean(dictionary_get_def(pinfo, + "pkg.location-independent", "false")); + + FILE* tixinfo_fp = fopen(tixinfo_rel, "w"); + if ( !tixinfo_fp ) + err(1, "`%s'", tixinfo_rel); + + fprintf(tixinfo_fp, "tix.version=1\n"); + fprintf(tixinfo_fp, "tix.class=tix\n"); + fprintf(tixinfo_fp, "tix.platform=%s\n", minfo->host); + fprintf(tixinfo_fp, "pkg.name=%s\n", minfo->package_name); + if ( alias ) + fprintf(tixinfo_fp, "pkg.alias-of=%s\n", alias); + else + { + if ( runtime_deps ) + fprintf(tixinfo_fp, "pkg.runtime-deps=%s\n", runtime_deps); + if ( location_independent ) + fprintf(tixinfo_fp, "pkg.location-independent=true\n"); + else + fprintf(tixinfo_fp, "pkg.prefix=%s\n", minfo->prefix); + } + + if ( ferror(tixinfo_fp) || fflush(tixinfo_fp) == EOF ) + err(1, "write: `%s'", tixinfo_rel); + + fclose(tixinfo_fp); + free(tardir_rel); + free(tixinfo_rel); +} + +static void Package(struct metainfo* minfo) +{ + if ( !fork_and_wait_or_recovery() ) + return; + + char* tardir_rel = join_paths(tmp_root, "tix"); + if ( !tardir_rel ) + err(1, "malloc"); + char* package_tix = print_string("%s/%s.tix.tar.xz", + minfo->destination, minfo->package_name); + if ( !package_tix ) + err(1, "malloc"); + printf("Creating `%s'...\n", package_tix); + + const char* cmd_argv[] = + { + minfo->tar, + "-C", tardir_rel, + "--remove-files", + "--create", + "--xz", + "--numeric-owner", + "--owner=0", + "--group=0", + "--file", package_tix, + "tix", + "data", + NULL + }; + recovery_execvp(cmd_argv[0], (char* const*) cmd_argv); + err(127, "%s", cmd_argv[0]); +} + +static void Compile(struct metainfo* minfo) +{ + string_array_t* pinfo = &minfo->package_info; + + // Detect which build system we are interfacing with. const char* build_system = dictionary_get(pinfo, "pkg.build-system"); - assert(build_system); + if ( !build_system ) + errx(1, "%s: pkg.build-system was not found", minfo->package_info_path); // Determine whether need to do an out-of-directory build. const char* use_build_dir_var = @@ -597,7 +822,11 @@ void BuildPackage(metainfo_t* minfo) bool use_build_dir = parse_boolean(use_build_dir_var); if ( use_build_dir ) { - minfo->build_dir = print_string("%s/build", tmp_root); + const char* build_rel = + minfo->bootstrapping ? "build-bootstrap" : "build"; + minfo->build_dir = join_paths(tmp_root, build_rel); + if ( !minfo->build_dir ) + err(1, "malloc"); if ( mkdir(minfo->build_dir, 0777) < 0 ) err(1, "mkdir %s", minfo->build_dir); } @@ -605,164 +834,142 @@ void BuildPackage(metainfo_t* minfo) minfo->build_dir = strdup(minfo->package_dir); // Reset the build directory if needed. - const char* default_clean_target = - !strcmp(build_system, "configure") ? "distclean" : "clean"; - const char* clean_target = dictionary_get_def(pinfo, "pkg.make.clean-target", - default_clean_target); - const char* ignore_clean_failure_var = - dictionary_get_def(pinfo, "pkg.make.ignore-clean-failure", "true"); - bool ignore_clean_failure = parse_boolean(ignore_clean_failure_var); - - const char* subdir = dictionary_get(pinfo, "pkg.subdir"); - if ( SHOULD_DO_BUILD_STEP(BUILD_STEP_PRE_CLEAN, minfo) && !use_build_dir && - IsDirty(minfo, NULL) ) - Make(minfo, clean_target, NULL, !ignore_clean_failure, NULL); + IsDirty(minfo) ) + Clean(minfo); // Configure the build directory if needed. if ( strcmp(build_system, "configure") == 0 && SHOULD_DO_BUILD_STEP(BUILD_STEP_CONFIGURE, minfo) ) - Configure(minfo, subdir); + Configure(minfo); + if ( SHOULD_DO_BUILD_STEP(BUILD_STEP_BUILD, minfo) ) + Build(minfo); + + if ( SHOULD_DO_BUILD_STEP(BUILD_STEP_INSTALL, minfo) ) + Install(minfo); + + if ( SHOULD_DO_BUILD_STEP(BUILD_STEP_POST_INSTALL, minfo) ) + PostInstall(minfo); + + // Clean the build directory after the successful build. + if ( SHOULD_DO_BUILD_STEP(BUILD_STEP_POST_CLEAN, minfo) ) + Clean(minfo); +} + +static void Bootstrap(struct metainfo* minfo) +{ + struct metainfo newinfo = { 0 }; + + newinfo.build = minfo->build; + newinfo.build_dir = NULL; + newinfo.destination = NULL; + newinfo.generation = minfo->generation; + newinfo.host = minfo->build; + newinfo.make = minfo->make; + newinfo.makeflags = minfo->makeflags; + newinfo.package_dir = minfo->package_dir; + newinfo.package_info_path = minfo->package_info_path; + newinfo.package_name = minfo->package_name; + newinfo.prefix = join_paths(tmp_root, "bootstrap"); + if ( !newinfo.prefix ) + err(1, "malloc"); + if ( mkdir(newinfo.prefix, 0777) < 0 ) + err(1, "mkdir: %s", newinfo.prefix); + newinfo.exec_prefix = newinfo.prefix; + newinfo.sysroot = NULL; + newinfo.tar = minfo->tar; + newinfo.target = minfo->host; + newinfo.tmp = minfo->tmp; + for ( size_t i = 0; i < minfo->package_info.length; i++ ) + { + const char* string = minfo->package_info.strings[i]; + if ( !strncmp(string, "pkg.", strlen("pkg.")) ) + continue; + if ( !strncmp(string, "bootstrap.", strlen("bootstrap.")) ) + { + const char* rest = string + strlen("bootstrap."); + char* newstring = print_string("pkg.%s", rest); + if ( !newstring ) + err(1, "malloc"); + if ( !string_array_append(&newinfo.package_info, newstring) ) + err(1, "malloc"); + free(newstring); + } + else + { + if ( !string_array_append(&newinfo.package_info, string) ) + err(1, "malloc"); + } + } + newinfo.start_step = BUILD_STEP_PRE_CLEAN; + newinfo.end_step = BUILD_STEP_POST_CLEAN; + newinfo.bootstrapping = true; + newinfo.cross = false; + + Compile(&newinfo); + + char* bindir = join_paths(newinfo.prefix, "bin"); + if ( !bindir ) + err(1, "malloc"); + if ( access(bindir, F_OK) == 0 ) + append_to_path(bindir); + free(bindir); + + char* sbindir = join_paths(newinfo.prefix, "sbin"); + if ( !sbindir ) + err(1, "malloc"); + if ( access(sbindir, F_OK) == 0 ) + append_to_path(sbindir); + free(sbindir); + + string_array_reset(&newinfo.package_info); + free(newinfo.prefix); +} + +static void BuildPackage(struct metainfo* minfo) +{ + string_array_t* pinfo = &minfo->package_info; + + // Whether this is just an alias for another package. + const char* alias = dictionary_get(pinfo, "pkg.alias-of"); + + // Determine if the package is location independent. bool location_independent = - parse_boolean(dictionary_get_def(pinfo, "pkg.location-independent", "false")); - - const char* build_target = dictionary_get_def(pinfo, "pkg.make.build-target", "all"); - const char* install_target = dictionary_get_def(pinfo, "pkg.make.install-target", "install"); - - if ( !location_independent && !minfo->prefix ) + parse_boolean(dictionary_get_def(pinfo, "pkg.location-independent", + "false")); + if ( !alias && !location_independent && !minfo->prefix ) errx(1, "error: %s is not location independent and you need to " "specify the intended destination prefix using --prefix", minfo->package_name); - if ( SHOULD_DO_BUILD_STEP(BUILD_STEP_BUILD, minfo) ) - Make(minfo, build_target, NULL, true, subdir); + CreateDestination(); - char* tardir_rel = print_string("%s/%s", tmp_root, "tix"); - if ( mkdir(tardir_rel, 0777) < 0 ) - err(1, "mkdir: %s", tardir_rel); + // Possibly build a native version of the package to aid cross-compilation. + // This is an anti-feature needed for broken packages that don't properly + // handle this case entirely themselves. There's a few packages that need + // the exact same version around natively in order to cross-compile. + const char* use_bootstrap_var = + dictionary_get_def(pinfo, "pkg.use-bootstrap", "false"); + bool use_bootstrap = parse_boolean(use_bootstrap_var); + if ( !alias && use_bootstrap && strcmp(minfo->build, minfo->host) != 0 && + SHOULD_DO_BUILD_STEP(BUILD_STEP_CONFIGURE, minfo) ) + Bootstrap(minfo); - char* destdir_rel = print_string("%s/%s", tardir_rel, "data"); - char* tixdir_rel = print_string("%s/%s", tardir_rel, "tix"); - char* tixinfo_rel = print_string("%s/%s", tardir_rel, "tix/tixinfo"); + EmitWrappers(minfo); - if ( mkdir(destdir_rel, 0755) != 0 ) - err(1, "mkdir: `%s'", destdir_rel); - if ( mkdir(tixdir_rel, 0755) != 0 ) - err(1, "mkdir: `%s'", tixdir_rel); - - char* destdir = realpath(destdir_rel, NULL); - if ( !destdir ) - err(1, "realpath: %s", destdir_rel); - - if ( SHOULD_DO_BUILD_STEP(BUILD_STEP_INSTALL, minfo) ) - Make(minfo, install_target, destdir, true, subdir); - - const char* post_install_cmd = dictionary_get(pinfo, "pkg.post-install.cmd"); - - if ( post_install_cmd && - SHOULD_DO_BUILD_STEP(BUILD_STEP_POST_INSTALL, minfo) && - fork_and_wait_or_recovery() ) - { - if ( chdir(minfo->package_dir) != 0 ) - err(1, "chdir: `%s'", minfo->package_dir); - setenv("TIX_BUILD_DIR", minfo->build_dir, 1); - setenv("TIX_SOURCE_DIR", minfo->package_dir, 1); - setenv("TIX_INSTALL_DIR", destdir, 1); - if ( minfo->sysroot ) - setenv("TIX_SYSROOT", minfo->sysroot, 1); - else - unsetenv("TIX_SYSROOT"); - setenv("BUILD", minfo->build, 1); - setenv("HOST", minfo->host, 1); - setenv("TARGET", minfo->target, 1); - if ( minfo->prefix ) - setenv("PREFIX", minfo->prefix, 1); - else - unsetenv("PREFIX"); - if ( minfo->exec_prefix ) - setenv("EXEC_PREFIX", minfo->exec_prefix, 1); - else - unsetenv("EXEC_PREFIX"); - const char* cmd_argv[] = - { - post_install_cmd, - NULL - }; - recovery_execvp(cmd_argv[0], (char* const*) cmd_argv); - err(127, "%s", cmd_argv[0]); - } - - const char* tix_ext = ".tix.tar.xz"; - char* package_tix = print_string("%s/%s%s", minfo->destination, - minfo->package_name, tix_ext); - - FILE* tixinfo_fp = fopen(tixinfo_rel, "w"); - if ( !tixinfo_fp ) - err(1, "`%s'", tixinfo_rel); - - const char* runtime_deps = dictionary_get(pinfo, "pkg.runtime-deps"); - - fprintf(tixinfo_fp, "tix.version=1\n"); - fprintf(tixinfo_fp, "tix.class=tix\n"); - fprintf(tixinfo_fp, "tix.platform=%s\n", minfo->host); - fprintf(tixinfo_fp, "pkg.name=%s\n", minfo->package_name); - if ( runtime_deps ) - fprintf(tixinfo_fp, "pkg.runtime-deps=%s\n", runtime_deps); - if ( location_independent ) - fprintf(tixinfo_fp, "pkg.location-independent=true\n"); - else - fprintf(tixinfo_fp, "pkg.prefix=%s\n", minfo->prefix); - - if ( ferror(tixinfo_fp) ) - err(1, "write: `%s'", tixinfo_rel); - - fclose(tixinfo_fp); + if ( !alias ) + Compile(minfo); if ( SHOULD_DO_BUILD_STEP(BUILD_STEP_PACKAGE, minfo) ) { - printf("Creating `%s'...\n", package_tix); - if ( fork_and_wait_or_recovery() ) - { - const char* cmd_argv[] = - { - minfo->tar, - "-C", tardir_rel, - "--remove-files", - "--create", - "--xz", - "--numeric-owner", - "--owner=0", - "--group=0", - "--file", package_tix, - "tix", - "data", - NULL - }; - recovery_execvp(cmd_argv[0], (char* const*) cmd_argv); - err(127, "%s", cmd_argv[0]); - } + TixInfo(minfo); + Package(minfo); } - - unlink(tixinfo_rel); - rmdir(destdir_rel); - rmdir(tixdir_rel); - //rmdir(tardir_rel); // Keep around to avoid on_exit handler race. - - free(tardir_rel); - free(destdir_rel); - free(tixdir_rel); - free(tixinfo_rel); - - free(package_tix); - - // Clean the build directory after the successful build. - if ( SHOULD_DO_BUILD_STEP(BUILD_STEP_POST_CLEAN, minfo) ) - Make(minfo, clean_target, NULL, !ignore_clean_failure, NULL); } -void VerifySourceTixInformation(metainfo_t* minfo) +static void VerifySourceTixInformation(struct metainfo* minfo) { const char* pipath = minfo->package_info_path; string_array_t* pinfo = &minfo->package_info; @@ -778,7 +985,8 @@ void VerifySourceTixInformation(metainfo_t* minfo) errx(1, "error: `%s': tix class `%s' is not `srctix': this object " "is not suitable for compilation.", pipath, tix_class); VerifyInfoVariable(pinfo, "pkg.name", pipath); - VerifyInfoVariable(pinfo, "pkg.build-system", pipath); + if ( !dictionary_get(pinfo, "pkg.alias-of") ) + VerifyInfoVariable(pinfo, "pkg.build-system", pipath); } // TODO: The MAKEFLAGS variable is actually not in the same format as the token @@ -786,7 +994,7 @@ void VerifySourceTixInformation(metainfo_t* minfo) // but instead consider them normal characters. This should work as // expected, though, as long as the MAKEFLAGS variable doesn't contain any // quote characters. -void PurifyMakeflags(void) +static void PurifyMakeflags(void) { const char* makeflags_environment = getenv("MAKEFLAGS"); if ( !makeflags_environment ) @@ -830,7 +1038,7 @@ int main(int argc, char* argv[]) { PurifyMakeflags(); - metainfo_t minfo; + struct metainfo minfo; memset(&minfo, 0, sizeof(minfo)); minfo.build = NULL; minfo.destination = strdup("."); @@ -846,6 +1054,7 @@ int main(int argc, char* argv[]) char* tmp = strdup(getenv_def("TMPDIR", "/tmp")); char* start_step_string = strdup("start"); char* end_step_string = strdup("end"); + char* source_package = NULL; const char* argv0 = argv[0]; for ( int i = 0; i < argc; i++ ) @@ -880,6 +1089,7 @@ int main(int argc, char* argv[]) else if ( GET_OPTION_VARIABLE("--make", &minfo.make) ) { } else if ( GET_OPTION_VARIABLE("--prefix", &minfo.prefix) ) { } else if ( GET_OPTION_VARIABLE("--exec-prefix", &minfo.exec_prefix) ) { } + else if ( GET_OPTION_VARIABLE("--source-package", &source_package) ) { } else if ( GET_OPTION_VARIABLE("--start", &start_step_string) ) { } else if ( GET_OPTION_VARIABLE("--sysroot", &minfo.sysroot) ) { } else if ( GET_OPTION_VARIABLE("--target", &minfo.target) ) { } @@ -933,9 +1143,10 @@ int main(int argc, char* argv[]) initialize_tmp(tmp, "tixbuild"); - minfo.package_dir = realpath(argv[1], NULL); + const char* srctix = argv[1]; + minfo.package_dir = realpath(srctix, NULL); if ( !minfo.package_dir ) - err(1, "realpath: %s", argv[1]); + err(1, "%s", srctix); if ( minfo.build && !minfo.build[0] ) free(minfo.build), minfo.build = NULL; @@ -951,14 +1162,17 @@ int main(int argc, char* argv[]) if ( !minfo.target ) minfo.target = strdup(minfo.host); + minfo.cross = strcmp(minfo.build, minfo.host) != 0 || minfo.sysroot; + if ( minfo.prefix && !minfo.exec_prefix ) minfo.exec_prefix = strdup(minfo.prefix); if ( !IsDirectory(minfo.package_dir) ) err(1, "`%s'", minfo.package_dir); - minfo.package_info_path = print_string("%s/tixbuildinfo", - minfo.package_dir); + minfo.package_info_path = join_paths(minfo.package_dir, "tixbuildinfo"); + if ( !minfo.package_info_path ) + err(1, "malloc"); minfo.package_info = string_array_make(); string_array_t* package_info = &minfo.package_info; @@ -972,7 +1186,23 @@ int main(int argc, char* argv[]) VerifySourceTixInformation(&minfo); minfo.package_name = strdup(dictionary_get(package_info, "pkg.name")); - emit_pkg_config_wrapper(&minfo); + const char* pkg_source_package = + dictionary_get(package_info, "pkg.source-package"); + if ( pkg_source_package && !source_package ) + { + source_package = print_string("%s/../%s", srctix, pkg_source_package); + if ( !source_package ) + err(1, "malloc"); + } + + if ( source_package ) + { + free(minfo.package_dir); + minfo.package_dir = realpath(source_package, NULL); + if ( !minfo.package_dir ) + err(1, "%s: looking for source package: %s", + srctix, source_package); + } BuildPackage(&minfo); diff --git a/tix/tix.c b/tix/tix.c index 1fce591a..bed658ad 100644 --- a/tix/tix.c +++ b/tix/tix.c @@ -105,6 +105,8 @@ string_array_t GetPackageDependencies(params_t* params, const char* pkg_name) const char* deps = dictionary_get_def(&tixinfo, "pkg.runtime-deps", ""); string_array_append_token_string(&ret, deps); + const char* alias = dictionary_get_def(&tixinfo, "pkg.alias-of", ""); + string_array_append_token_string(&ret, alias); string_array_reset(&tixinfo);