aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2023-02-22 10:20:14 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2023-02-22 10:20:14 +0200
commit5837974ede1f489fe1e65cb10188f776fb6d1974 (patch)
tree958b345fd8b3490b358ca0807a1d3c220fc89fab
parent10827e2338f9390383c30c95a2cbbfd733d76088 (diff)
WIP
-rw-r--r--bpkg/package.hxx6
-rw-r--r--bpkg/pkg-bindist.cli12
-rw-r--r--bpkg/pkg-bindist.cxx28
-rw-r--r--bpkg/system-package-manager-debian.cxx184
-rw-r--r--bpkg/system-package-manager.hxx13
-rw-r--r--bpkg/utility.cxx20
-rw-r--r--bpkg/utility.hxx3
-rw-r--r--bpkg/utility.txx11
8 files changed, 234 insertions, 43 deletions
diff --git a/bpkg/package.hxx b/bpkg/package.hxx
index 70fcee2..1c70676 100644
--- a/bpkg/package.hxx
+++ b/bpkg/package.hxx
@@ -1331,8 +1331,7 @@ namespace bpkg
return src_root->absolute () ? *src_root : configuration / *src_root;
}
- // Return the output directory using the configuration directory. Note
- // that the output directory is always relative.
+ // Return the output directory using the configuration directory.
//
dir_path
effective_out_root (const dir_path& configuration) const
@@ -1340,6 +1339,9 @@ namespace bpkg
// Cast for compiling with ODB (see above).
//
assert (static_cast<bool> (out_root));
+
+ // Note that out_root is always relative.
+ //
return configuration / *out_root;
}
diff --git a/bpkg/pkg-bindist.cli b/bpkg/pkg-bindist.cli
index 23c70d1..eef0c1e 100644
--- a/bpkg/pkg-bindist.cli
+++ b/bpkg/pkg-bindist.cli
@@ -145,12 +145,12 @@ namespace bpkg
bool --private
{
"Enable the private installation subdirectory functionality using the
- binary package name as the private subdirectory. This is primarily
- useful when bundling dependencies, such as shared libraries, of an
- executable that is being installed into a shared location, such as
- \cb{/usr/}. See the \cb{config.install.private} configuration variable
- documentation in the build system manual for details. This option
- only makes sense together with \cb{--recursive}."
+ package name as the private subdirectory. This is primarily useful
+ when bundling dependencies, such as shared libraries, of an executable
+ that is being installed into a shared location, such as \cb{/usr/}.
+ See the \cb{config.install.private} configuration variable
+ documentation in the build system manual for details. This option only
+ makes sense together with \cb{--recursive}."
}
bool --wipe-out
diff --git a/bpkg/pkg-bindist.cxx b/bpkg/pkg-bindist.cxx
index e191996..6db7cdb 100644
--- a/bpkg/pkg-bindist.cxx
+++ b/bpkg/pkg-bindist.cxx
@@ -16,6 +16,7 @@ using namespace butl;
namespace bpkg
{
+ using package = system_package_manager::package;
using packages = system_package_manager::packages;
using recursive_mode = system_package_manager::recursive_mode;
@@ -131,13 +132,11 @@ namespace bpkg
// Skip duplicates.
//
- if (ps == nullptr ||
- find_if (ps->begin (), ps->end (),
- [&d] (const pair<shared_ptr<selected_package>,
- available_packages>& p)
- {
- return p.first == d;
- }) == ps->end ())
+ if (ps == nullptr || find_if (ps->begin (), ps->end (),
+ [&d] (const package& p)
+ {
+ return p.selected == d;
+ }) == ps->end ())
{
const selected_package& p (*d);
@@ -155,7 +154,13 @@ namespace bpkg
}
if (ps != nullptr)
- ps->push_back (make_pair (move (d), move (aps)));
+ {
+ dir_path out;
+ if (ps != &deps)
+ out = p.effective_out_root (db.config);
+
+ ps->push_back (package {move (d), move (aps), move (out)});
+ }
}
if (recursive && !sys)
@@ -308,7 +313,8 @@ namespace bpkg
merge_languages (type, langs, *ap);
const selected_package& r (*p);
- pkgs.push_back (make_pair (move (p), move (aps)));
+ pkgs.push_back (
+ package {move (p), move (aps), r.effective_out_root (db.config)});
// If --recursive is not specified then we want all the immediate
// (system and non-) dependecies in deps. Otherwise, if the recursive
@@ -336,7 +342,7 @@ namespace bpkg
// Load the package manifest (source of extra metadata). This should be
// always possible since the package is configured and is not system.
//
- const shared_ptr<selected_package>& sp (pkgs.front ().first);
+ const shared_ptr<selected_package>& sp (pkgs.front ().selected);
package_manifest pm (
pkg_verify (o,
@@ -374,7 +380,7 @@ namespace bpkg
//
if (verb && !o.no_result ())
{
- const selected_package& p (*pkgs.front ().first);
+ const selected_package& p (*pkgs.front ().selected);
text << "generated " << spm->os_release.name_id << " package for "
<< p.name << '/' << p.version;
diff --git a/bpkg/system-package-manager-debian.cxx b/bpkg/system-package-manager-debian.cxx
index e78d970..3d9b5d5 100644
--- a/bpkg/system-package-manager-debian.cxx
+++ b/bpkg/system-package-manager-debian.cxx
@@ -1853,15 +1853,15 @@ namespace bpkg
const string& pt,
const small_vector<language, 1>& langs,
const dir_path& out,
- optional<recursive_mode>)
+ optional<recursive_mode> recur)
{
assert (!langs.empty ()); // Should be effective.
- const shared_ptr<selected_package>& sp (pkgs.front ().first);
+ const shared_ptr<selected_package>& sp (pkgs.front ().selected);
const package_name& pn (sp->name);
const version& pv (sp->version);
- const available_packages& aps (pkgs.front ().second);
+ const available_packages& aps (pkgs.front ().available);
bool lib (pt == "lib");
@@ -1897,10 +1897,10 @@ namespace bpkg
vector<package_status> sdeps;
sdeps.reserve (deps.size ());
- for (const pair<shared_ptr<selected_package>, available_packages>& p: deps)
+ for (const package& p: deps)
{
- const shared_ptr<selected_package>& sp (p.first);
- const available_packages& aps (p.second);
+ const shared_ptr<selected_package>& sp (p.selected);
+ const available_packages& aps (p.available);
package_status s;
if (sp->substate == package_substate::system)
@@ -2030,7 +2030,7 @@ namespace bpkg
if (!e->comment.empty ())
maintainer = e->comment;
else
- maintainer = pn.string () + " maintainer";
+ maintainer = pn.string () + " package maintainer";
maintainer += " <" + *e + '>';
}
@@ -2465,18 +2465,131 @@ namespace bpkg
// See debhelper(7) for details on these.
//
if (verb == 0)
- os << "export DH_QUIET=1\n"
+ os << "export DH_QUIET := 1\n"
<< '\n';
else if (verb == 1)
os << "# Uncomment this to turn on verbose mode.\n"
- << "#export DH_VERBOSE=1\n"
+ << "#export DH_VERBOSE := 1\n"
<< '\n';
else
- os << "export DH_VERBOSE=1\n"
+ os << "export DH_VERBOSE := 1\n"
<< '\n';
+ // We could have instead included architecture.mk but let's avoid an
+ // extra dependency (most packages that we sampled do it directly).
+ //
+ os << "DEB_HOST_MULTIARCH ?= $(shell dpkg-architecture -qDEB_HOST_MULTIARCH)\n"
+ << '\n';
+
+ // The debian/tmp/ subdirectory appears to be the canonical destination
+ // directory (see dh_auto_install(1) for details).
+ //
+ os << "DESTDIR := $(CURDIR)/debian/tmp" << '\n'
+ << '\n';
+
+ // Let's use absolute path to the build system driver in case we are
+ // invoked with altered environment or some such.
+ //
+ // See --jobs documentation in dpkg-buildpackage(1) for details on
+ // parallel=N.
+ //
+ os << "b := " << search_b (*ops_).effect_string () << '\n'
+ << '\n'
+ << "parallel := $(filter parallel=%,$(DEB_BUILD_OPTIONS))" << '\n'
+ << "ifneq ($(parallel),)" << '\n'
+ << " parallel := $(patsubst parallel=%,%,$(parallel))" << '\n'
+ << " ifeq ($(parallel),1)" << '\n'
+ << " b += --serial-stop" << '\n'
+ << " else" << '\n'
+ << " b += --jobs=$(parallel)" << '\n'
+ << " endif" << '\n'
+ << "endif" << '\n'
+ << '\n';
+
+ // Note that we override every config.install.* variable in order not to
+ // pick anything configured.
+ //
+ // We make use of the <project> substitution since in the recursive mode
+ // we may be installing multiple projects. Note that the <private>
+ // directory component is automatically removed if this functionality is
+ // not enabled. One side-effect of using <project> is that we will be
+ // using the bpkg package name instead of the main Debian package name.
+ // But perhaps that's correct: on Debian it's usually the source package
+ // name, which is the same. To keep things consistent we use the bpkg
+ // package name for <private> as well.
+ //
+ // @@ Some libraries install what looks like architecture-specific
+ // configuration files to /usr/include/$(DEB_HOST_MULTIARCH). Maybe
+ // we should invent something like config.install.include_arch to
+ // support this distinction?
+ //
+ bool priv (ops_->private_ ());
+
+ os << "config := config.install.chroot=$(DESTDIR)/" << '\n'
+ << "config += 'config.install.sudo=[null]'" << '\n'
+
+ << "config += config.install.root=/usr/" << '\n'
+ << "config += config.install.data_root=root/" << '\n'
+ << "config += config.install.exec_root=root/" << '\n'
+
+ << "config += config.install.bin=exec_root/bin/" << '\n'
+ << "config += config.install.sbin=exec_root/sbin/" << '\n'
+
+ // On Debian shared libraries should not be executable. Also,
+ // libexec/ is the same as lib/ (note that executables that get
+ // installed there will still have the executable bit set).
+ //
+ << "config += 'config.install.lib=exec_root/lib/$(DEB_HOST_MULTIARCH)/<private>/'" << '\n'
+ << "config += config.install.lib.mode=644" << '\n'
+ << "config += 'config.install.libexec=lib/<project>/'" << '\n'
+ << "config += config.install.pkgconfig=lib/pkgconfig/" << '\n'
+
+ << "config += config.install.etc=data_root/etc/" << '\n'
+ << "config += 'config.install.include=data_root/include/<private>/'" << '\n'
+ << "config += config.install.share=data_root/share/" << '\n'
+ << "config += 'config.install.data=share/<private>/<project>/'" << '\n'
+
+ << "config += 'config.install.doc=share/doc/<private>/<project>/'" << '\n'
+ << "config += config.install.legal=doc/" << '\n'
+ << "config += config.install.man=share/man/" << '\n'
+ << "config += config.install.man1=share/man1/" << '\n'
+ << "config += config.install.man2=share/man2/" << '\n'
+ << "config += config.install.man3=share/man3/" << '\n'
+ << "config += config.install.man4=share/man4/" << '\n'
+ << "config += config.install.man5=share/man5/" << '\n'
+ << "config += config.install.man6=share/man6/" << '\n'
+ << "config += config.install.man7=share/man7/" << '\n'
+ << "config += config.install.man8=share/man8/" << '\n'
+
+ << "config += 'config.install.private="
+ << (priv ? pn.string () : "[null]") << "'" << '\n';
+
+ // If this is a C-based language, add rpath for private installation.
+ //
+ if (priv && (lang ("c") || lang ("c++") || lang ("cc")))
+ os << "config += config.bin.rpath=/usr/lib/$(DEB_HOST_MULTIARCH)/"
+ << pn << "/" << '\n';
+
+ os << '\n';
+
+ // List of packages we need to install.
+ //
+ for (auto b (pkgs.begin ()), i (b); i != pkgs.end (); ++i)
+ {
+ os << "packages" << (i == b ? " := " : " += ")
+ << i->out_root.representation () << '\n';
+ }
+ os << '\n';
+
+ // Disable synchronization hooks for good measure.
+ //
+ os << "export BDEP_SYNC := 0\n"
+ << '\n';
+
+ // Default to the dh command sequencer.
+ //
os << "%:\n"
- << "\tdh $@\n"
+ << '\t' << "dh $@" << '\n'
<< '\n';
// Override dh_auto_configure.
@@ -2486,7 +2599,43 @@ namespace bpkg
<< "override_dh_auto_configure:\n"
<< '\n';
- // @@ TODO: remember to override config.install.sudo.
+ // Override dh_auto_build.
+ //
+ os << "override_dh_auto_build:\n"
+ << '\t' << "$b $(config) update-for-install: $(packages)" << '\n'
+ << '\n';
+
+ // Override dh_auto_test.
+ //
+ // Note that running tests after update-for-install may cause rebuild
+ // (e.g., relinking without rpath, etc) before tests and again before
+ // install. So doesn't seem worth the trouble.
+ //
+ os << "# Assume any testing has already been done.\n"
+ << "#\n"
+ << "override_dh_auto_test:\n"
+ << '\n';
+
+ // Override dh_auto_install.
+ //
+ // Note that we have to use global install scope for the auto recursive
+ // mode since things can be spread over multiple linked configurations.
+ //
+ string scope (!recur || *recur == recursive_mode::full
+ ? "project"
+ : "global");
+
+ os << "override_dh_auto_install:\n"
+ << '\t' << "$b $(config) '!config.install.scope=" << scope << "' "
+ << "install: $(packages)" << '\n'
+ << '\n';
+
+ // Override dh_auto_clean.
+ //
+ os << "# This is not a real source directory so nothing to clean.\n"
+ << "#\n"
+ << "override_dh_auto_clean:\n"
+ << '\n';
os.close ();
}
@@ -2495,6 +2644,17 @@ namespace bpkg
fail << "unable to write to " << rules << ": " << e;
}
+ // Call dpkg-buildpackage.
+ //
+ // @@ Pass our --jobs as --jobs=N.
+ // @@ Buildinfo stuff fuzzy.
+ //
+ // --no-sign
+ // --target-arch
+ //
+ // cd src/
+ // dpkg-buildpackage --no-sign --build=binary
+
// Cleanup intermediate files unless requested not to.
//
if (!ops_->keep_out ())
diff --git a/bpkg/system-package-manager.hxx b/bpkg/system-package-manager.hxx
index 29449f6..28b0c17 100644
--- a/bpkg/system-package-manager.hxx
+++ b/bpkg/system-package-manager.hxx
@@ -156,7 +156,8 @@ namespace bpkg
//
// The available packages are loaded for all the packages in pkgs and
// deps. For non-system packages (so for all in pkgs) there is always a
- // single available package that corresponds to the selected package.
+ // single available package that corresponds to the selected package. The
+ // out_root is only set for packages in pkgs.
//
// The passed package manifest corresponds to the first package in pkgs
// (normally used as a source of additional package metadata such as
@@ -171,8 +172,14 @@ namespace bpkg
// See the pkg-bindist(1) man page and the pkg_bindist() function
// implementation for background and details.
//
- using packages =
- vector<pair<shared_ptr<selected_package>, available_packages>>;
+ struct package // @@ TODO: any better name?
+ {
+ shared_ptr<selected_package> selected;
+ available_packages available;
+ dir_path out_root; // Absolute and normalized.
+ };
+
+ using packages = vector<package>;
enum class recursive_mode {auto_, full};
diff --git a/bpkg/utility.cxx b/bpkg/utility.cxx
index b79c85b..96fda0f 100644
--- a/bpkg/utility.cxx
+++ b/bpkg/utility.cxx
@@ -369,6 +369,26 @@ namespace bpkg
: BPKG_EXE_PREFIX "b" BPKG_EXE_SUFFIX;
}
+ process_path
+ search_b (const common_options& co)
+ {
+ const char* b (name_b (co));
+
+ try
+ {
+ // Use our executable directory as a fallback search since normally the
+ // entire toolchain is installed into one directory. This way, for
+ // example, if we installed into /opt/build2 and run bpkg with absolute
+ // path (and without PATH), then bpkg will be able to find "its" b.
+ //
+ return process::path_search (b, exec_dir);
+ }
+ catch (const process_error& e)
+ {
+ fail << "unable to execute " << b << ": " << e << endf;
+ }
+ }
+
void
dump_stderr (auto_fd&& fd)
{
diff --git a/bpkg/utility.hxx b/bpkg/utility.hxx
index 69a02d3..79534f0 100644
--- a/bpkg/utility.hxx
+++ b/bpkg/utility.hxx
@@ -247,6 +247,9 @@ namespace bpkg
const char*
name_b (const common_options&);
+ process_path
+ search_b (const common_options&);
+
template <typename O, typename E, typename... A>
process
start_b (const common_options&, O&& out, E&& err, verb_b, A&&... args);
diff --git a/bpkg/utility.txx b/bpkg/utility.txx
index 6113e4e..0f88d53 100644
--- a/bpkg/utility.txx
+++ b/bpkg/utility.txx
@@ -15,17 +15,10 @@ namespace bpkg
verb_b v,
A&&... args)
{
- const char* b (name_b (co));
+ process_path pp (search_b (co));
try
{
- // Use our executable directory as a fallback search since normally the
- // entire toolchain is installed into one directory. This way, for
- // example, if we installed into /opt/build2 and run bpkg with absolute
- // path (and without PATH), then bpkg will be able to find "its" b.
- //
- process_path pp (process::path_search (b, exec_dir));
-
small_vector<const char*, 1> ops;
// Map verbosity level. If we are running quiet or at level 1,
@@ -98,7 +91,7 @@ namespace bpkg
}
catch (const process_error& e)
{
- fail << "unable to execute " << b << ": " << e << endf;
+ fail << "unable to execute " << pp.recall_string () << ": " << e << endf;
}
}