aboutsummaryrefslogtreecommitdiff
path: root/libbuild2/cc
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2022-11-22 06:27:33 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2022-11-22 06:27:33 +0200
commitf19959de304afaff2b3d539c9bef1f493ede5fbd (patch)
tree66cbbbea6eb866b59154f8985d60d7d96fc3e3e2 /libbuild2/cc
parentcf652392b0d0a88899ac4178851affef43af1631 (diff)
Add support for Objective-C/C++ compilation in cc module
Diffstat (limited to 'libbuild2/cc')
-rw-r--r--libbuild2/cc/common.hxx29
-rw-r--r--libbuild2/cc/compile-rule.cxx54
-rw-r--r--libbuild2/cc/compile-rule.hxx2
-rw-r--r--libbuild2/cc/install-rule.cxx6
-rw-r--r--libbuild2/cc/link-rule.cxx79
-rw-r--r--libbuild2/cc/module.cxx3
-rw-r--r--libbuild2/cc/target.cxx19
-rw-r--r--libbuild2/cc/target.hxx16
8 files changed, 140 insertions, 68 deletions
diff --git a/libbuild2/cc/common.hxx b/libbuild2/cc/common.hxx
index c11fa7a..4ad0e22 100644
--- a/libbuild2/cc/common.hxx
+++ b/libbuild2/cc/common.hxx
@@ -32,10 +32,12 @@ namespace build2
{
lang x_lang;
- const char* x; // Module name ("c", "cxx").
- const char* x_name; // Compiler name ("c", "c++").
- const char* x_default; // Compiler default ("gcc", "g++").
- const char* x_pext; // Preprocessed source extension (".i", ".ii").
+ const char* x; // Module name ("c", "cxx").
+ const char* x_name; // Compiler name ("c", "c++").
+ const char* x_obj_name; // Same for Objective-X ("obj-c", "obj-c++").
+ const char* x_default; // Compiler default ("gcc", "g++").
+ const char* x_pext; // Preprocessed source extension (".i", ".ii").
+ const char* x_obj_pext; // Same for Objective-X (".mi", ".mii").
// Array of modules that can hint us the toolchain, terminate with
// NULL.
@@ -210,8 +212,22 @@ namespace build2
size_t sys_lib_dirs_extra; // First trailing extra entry (size if none).
size_t sys_hdr_dirs_extra;
+ // Note that x_obj is patched in by the x.objx module. So it stays NULL
+ // if Objective-X compilation is not enabled.
+ //
const target_type& x_src; // Source target type (c{}, cxx{}).
const target_type* x_mod; // Module target type (mxx{}), if any.
+ const target_type* x_obj; // Objective-X target type (m{}, mm{}).
+
+ // Check if an object (target, prerequisite, etc) is an Objective-X
+ // source.
+ //
+ template <typename T>
+ bool
+ x_objective (const T& t) const
+ {
+ return x_obj != nullptr && t.is_a (*x_obj);
+ }
// Array of target types that are considered the X-language headers
// (excluding h{} except for C). Keep them in the most likely to appear
@@ -219,6 +235,8 @@ namespace build2
//
const target_type* const* x_hdr;
+ // Check if an object (target, prerequisite, etc) is a header.
+ //
template <typename T>
bool
x_header (const T& t, bool c_hdr = true) const
@@ -283,7 +301,8 @@ namespace build2
sys_lib_dirs_mode (slm), sys_hdr_dirs_mode (shm),
sys_mod_dirs_mode (smm),
sys_lib_dirs_extra (sle), sys_hdr_dirs_extra (she),
- x_src (src), x_mod (mod), x_hdr (hdr), x_inc (inc) {}
+ x_src (src), x_mod (mod), x_obj (nullptr),
+ x_hdr (hdr), x_inc (inc) {}
};
class LIBBUILD2_CC_SYMEXPORT common: public data
diff --git a/libbuild2/cc/compile-rule.cxx b/libbuild2/cc/compile-rule.cxx
index 5693334..6ca1f0a 100644
--- a/libbuild2/cc/compile-rule.cxx
+++ b/libbuild2/cc/compile-rule.cxx
@@ -232,7 +232,8 @@ namespace build2
// Note that we don't really need this for clean (where we only need
// unrefined unit type) so we could make this update-only. But let's keep
- // it simple for now.
+ // it simple for now. Note that now we do need the source prerequisite
+ // type in clean to deal with Objective-X.
//
struct compile_rule::match_data
{
@@ -369,11 +370,13 @@ namespace build2
case unit_type::non_modular:
case unit_type::module_impl:
{
+ bool obj (x_objective (md.src));
+
o1 = "-x";
switch (x_lang)
{
- case lang::c: o2 = "c"; break;
- case lang::cxx: o2 = "c++"; break;
+ case lang::c: o2 = obj ? "objective-c" : "c"; break;
+ case lang::cxx: o2 = obj ? "objective-c++" : "c++"; break;
}
break;
}
@@ -475,7 +478,7 @@ namespace build2
//
if (ut == unit_type::module_header ? p.is_a (**x_hdr) || p.is_a<h> () :
ut == unit_type::module_intf ? p.is_a (*x_mod) :
- p.is_a (x_src))
+ p.is_a (x_src) || (x_obj != nullptr && p.is_a (*x_obj)))
{
// Save in the target's auxiliary storage.
//
@@ -1530,10 +1533,13 @@ namespace build2
switch (a)
{
case perform_update_id: return move (md);
- case perform_clean_id: return [this] (action a, const target& t)
+ case perform_clean_id:
{
- return perform_clean (a, t);
- };
+ return [this, srct = &md.src.type ()] (action a, const target& t)
+ {
+ return perform_clean (a, t, *srct);
+ };
+ }
default: return noop_recipe; // Configure update.
}
}
@@ -3012,6 +3018,10 @@ namespace build2
file_cache::entry psrc;
bool puse (true);
+ // Preprocessed file extension.
+ //
+ const char* pext (x_objective (src) ? x_obj_pext : x_pext);
+
// Preprocesor mode that preserves as much information as possible while
// still performing inclusions. Also serves as a flag indicating whether
// this compiler uses the separate preprocess and compile setup.
@@ -3210,7 +3220,7 @@ namespace build2
// Return NULL if the dependency information goes to stdout and a
// pointer to the temporary file path otherwise.
//
- auto init_args = [a, &t, ot, li, reprocess,
+ auto init_args = [a, &t, ot, li, reprocess, pext,
&src, &md, &psrc, &sense_diag, &mod_mapper, &bs,
pp, &env, &args, &args_gen, &args_i, &out, &drm,
&so_map, this]
@@ -3436,7 +3446,7 @@ namespace build2
msvc_sanitize_cl (args);
- psrc = ctx.fcache.create (t.path () + x_pext, !modules);
+ psrc = ctx.fcache.create (t.path () + pext, !modules);
if (fc)
{
@@ -3583,7 +3593,7 @@ namespace build2
// Preprocessor output.
//
- psrc = ctx.fcache.create (t.path () + x_pext, !modules);
+ psrc = ctx.fcache.create (t.path () + pext, !modules);
args.push_back ("-o");
args.push_back (psrc.path ().string ().c_str ());
}
@@ -3878,7 +3888,7 @@ namespace build2
if (modules && (ctype != compiler_type::msvc ||
md.type != unit_type::module_intf))
{
- result.first = ctx.fcache.create_existing (t.path () + x_pext);
+ result.first = ctx.fcache.create_existing (t.path () + pext);
result.second = true;
}
@@ -7247,7 +7257,7 @@ namespace build2
// @@ TODO: why don't we print env (here and/or below)? Also link rule.
//
if (verb == 1)
- print_diag (x_name, s, t);
+ print_diag (x_objective (s) ? x_obj_name : x_name, s, t);
else if (verb == 2)
print_process (args);
@@ -7470,25 +7480,25 @@ namespace build2
}
target_state compile_rule::
- perform_clean (action a, const target& xt) const
+ perform_clean (action a, const target& xt, const target_type& srct) const
{
const file& t (xt.as<file> ());
+ // Preprocessed file extension.
+ //
+ const char* pext (x_objective (srct) ? x_obj_pext : x_pext);
+
// Compressed preprocessed file extension.
//
- auto cpext = [this, &t, s = string ()] () mutable -> const char*
- {
- return (s = t.ctx.fcache.compressed_extension (x_pext)).c_str ();
- };
+ string cpext (t.ctx.fcache.compressed_extension (pext));
clean_extras extras;
-
switch (ctype)
{
- case compiler_type::gcc: extras = {".d", x_pext, cpext (), ".t"}; break;
- case compiler_type::clang: extras = {".d", x_pext, cpext ()}; break;
- case compiler_type::msvc: extras = {".d", x_pext, cpext (), ".idb", ".pdb"};break;
- case compiler_type::icc: extras = {".d"}; break;
+ case compiler_type::gcc: extras = {".d", pext, cpext.c_str (), ".t"}; break;
+ case compiler_type::clang: extras = {".d", pext, cpext.c_str ()}; break;
+ case compiler_type::msvc: extras = {".d", pext, cpext.c_str (), ".idb", ".pdb"}; break;
+ case compiler_type::icc: extras = {".d"}; break;
}
return perform_clean_extra (a, t, extras);
diff --git a/libbuild2/cc/compile-rule.hxx b/libbuild2/cc/compile-rule.hxx
index cfe0dd7..a9a22c4 100644
--- a/libbuild2/cc/compile-rule.hxx
+++ b/libbuild2/cc/compile-rule.hxx
@@ -58,7 +58,7 @@ namespace build2
perform_update (action, const target&, match_data&) const;
target_state
- perform_clean (action, const target&) const;
+ perform_clean (action, const target&, const target_type&) const;
public:
using appended_libraries = small_vector<const target*, 256>;
diff --git a/libbuild2/cc/install-rule.cxx b/libbuild2/cc/install-rule.cxx
index 5118332..640612c 100644
--- a/libbuild2/cc/install-rule.cxx
+++ b/libbuild2/cc/install-rule.cxx
@@ -90,7 +90,8 @@ namespace build2
{
return (x_header (p) ||
p.is_a (x_src) ||
- (x_mod != nullptr && p.is_a (*x_mod)));
+ (x_mod != nullptr && p.is_a (*x_mod)) ||
+ (x_obj != nullptr && p.is_a (*x_obj)));
};
if (t.is_a<exe> ())
@@ -338,7 +339,8 @@ namespace build2
{
return (x_header (p) ||
p.is_a (x_src) ||
- (x_mod != nullptr && p.is_a (*x_mod)));
+ (x_mod != nullptr && p.is_a (*x_mod)) ||
+ (x_obj != nullptr && p.is_a (*x_obj)));
};
if (t.is_a<libue> ())
diff --git a/libbuild2/cc/link-rule.cxx b/libbuild2/cc/link-rule.cxx
index 24dc373..9bf86e6 100644
--- a/libbuild2/cc/link-rule.cxx
+++ b/libbuild2/cc/link-rule.cxx
@@ -290,12 +290,14 @@ namespace build2
if (p.is_a (x_src) ||
(x_mod != nullptr && p.is_a (*x_mod)) ||
+ (x_obj != nullptr && p.is_a (*x_obj)) ||
// Header-only X library (or library with C source and X header).
(library && x_header (p, false /* c_hdr */)))
{
r.seen_x = true;
}
- else if (p.is_a<c> () ||
+ else if (p.is_a<c> () ||
+ (x_obj != nullptr && p.is_a<m> ()) ||
// Header-only C library.
(library && p.is_a<h> ()))
{
@@ -997,9 +999,9 @@ namespace build2
//
#if 1
if (!um)
- um = (p.is_a (x_src) ||
- p.is_a<c> () ||
- (x_mod != nullptr && p.is_a (*x_mod)) ||
+ um = (p.is_a (x_src) || p.is_a<c> () ||
+ (x_mod != nullptr && p.is_a (*x_mod)) ||
+ (x_obj != nullptr && (p.is_a (*x_obj) || p.is_a<m> ())) ||
x_header (p, true));
#endif
@@ -1023,12 +1025,14 @@ namespace build2
// 2 - mod
// 3 - obj/bmi and also lib not to be cleaned (and other stuff)
//
- uint8_t m (0);
+ uint8_t mk (0);
bool mod (x_mod != nullptr && p.is_a (*x_mod));
bool hdr (false);
- if (mod || p.is_a (x_src) || p.is_a<c> ())
+ if (mod ||
+ p.is_a (x_src) || p.is_a<c> () ||
+ (x_obj != nullptr && (p.is_a (*x_obj) || p.is_a<m> ())))
{
binless = binless && (mod ? user_binless : false);
@@ -1116,7 +1120,7 @@ namespace build2
}
pt = &r.first;
- m = mod ? 2 : 1;
+ mk = mod ? 2 : 1;
}
else if (p.is_a<libx> () ||
p.is_a<liba> () ||
@@ -1134,7 +1138,7 @@ namespace build2
pt = &p.search (t);
if (skip (*pt))
- m = 3; // Mark so it is not matched.
+ mk = 3; // Mark so it is not matched.
// If this is the lib{}/libul{} group, then pick the appropriate
// member. Also note this in prerequisite_target::include (used
@@ -1206,7 +1210,7 @@ namespace build2
!pt->is_a<hbmix> () &&
cast_false<bool> ((*pt)[b_binless])));
- m = 3;
+ mk = 3;
}
if (user_binless && !binless)
@@ -1226,18 +1230,18 @@ namespace build2
if (*um)
{
- if (m != 3)
+ if (mk != 3)
fail << "unable to update during match prerequisite " << p <<
info << "updating this type of prerequisites during match is "
<< "not supported by this rule";
- m = 0;
+ mk = 0;
pto.include |= prerequisite_target::include_udm;
update_match = true;
}
}
- mark (pt, m);
+ mark (pt, mk);
}
// Match lib{} first and then update during match (the only unmarked) in
@@ -1711,20 +1715,20 @@ namespace build2
// 1 - completion
// 2 - verification
//
- uint8_t m (unmark (pt));
+ uint8_t mk (unmark (pt));
- if (m == 3) // obj/bmi or lib not to be cleaned
+ if (mk == 3) // obj/bmi or lib not to be cleaned
{
- m = 1; // Just completion.
+ mk = 1; // Just completion.
// Note that if this is a library not to be cleaned, we keep it
// marked for completion (see the next phase).
}
- else if (m == 1 || m == 2) // Source/module chain.
+ else if (mk == 1 || mk == 2) // Source/module chain.
{
- bool mod (m == 2);
+ bool mod (mk == 2); // p is_a x_mod
- m = 1;
+ mk = 1;
const target& rt (*pt);
bool group (!p.prerequisite.belongs (t)); // Group's prerequisite.
@@ -1875,7 +1879,10 @@ namespace build2
// Most of the time we will have just a single source so fast-
// path that case.
//
- if (p1.is_a (mod ? *x_mod : x_src) || p1.is_a<c> ())
+ if (mod
+ ? p1.is_a (*x_mod)
+ : (p1.is_a (x_src) || p1.is_a<c> () ||
+ (x_obj != nullptr && (p1.is_a (*x_obj) || p1.is_a<m> ()))))
{
src = true;
continue; // Check the rest of the prerequisites.
@@ -1888,8 +1895,11 @@ namespace build2
p1.is_a<libx> () ||
p1.is_a<liba> () || p1.is_a<libs> () || p1.is_a<libux> () ||
p1.is_a<bmi> () || p1.is_a<bmix> () ||
- (p.is_a (mod ? *x_mod : x_src) && x_header (p1)) ||
- (p.is_a<c> () && p1.is_a<h> ()))
+ ((mod ||
+ p.is_a (x_src) ||
+ (x_obj != nullptr && p.is_a (*x_obj))) && x_header (p1)) ||
+ ((p.is_a<c> () ||
+ (x_obj != nullptr && p.is_a<m> ())) && p1.is_a<h> ()))
continue;
fail << "synthesized dependency for prerequisite " << p
@@ -1902,11 +1912,11 @@ namespace build2
if (!src)
fail << "synthesized dependency for prerequisite " << p
<< " would be incompatible with existing target " << *pt <<
- info << "no existing c/" << x_name << " source prerequisite" <<
+ info << "no existing c/" << x_lang << " source prerequisite" <<
info << "specify corresponding " << rtt.name << "{} "
<< "dependency explicitly";
- m = 2; // Needs verification.
+ mk = 2; // Needs verification.
}
}
else // lib*{} or update during match
@@ -1948,7 +1958,7 @@ namespace build2
}
}
- mark (pt, m);
+ mark (pt, mk);
}
// Process prerequisites, pass 3: match everything and verify chains.
@@ -1964,7 +1974,7 @@ namespace build2
bool adhoc (pts[i].adhoc ());
const target*& pt (pts[i++]);
- uint8_t m;
+ uint8_t mk;
if (pt == nullptr)
{
@@ -1974,13 +1984,13 @@ namespace build2
continue;
pt = &p.search (t);
- m = 1; // Mark for completion.
+ mk = 1; // Mark for completion.
}
else
{
- m = unmark (pt);
+ mk = unmark (pt);
- if (m == 0)
+ if (mk == 0)
continue; // Already matched.
// If this is a library not to be cleaned, we can finally blank it
@@ -1994,7 +2004,7 @@ namespace build2
}
match_async (a, *pt, ctx.count_busy (), t[a].task_count);
- mark (pt, m);
+ mark (pt, mk);
}
wg.wait ();
@@ -2009,15 +2019,15 @@ namespace build2
// Skipped or not marked for completion.
//
- uint8_t m;
- if (pt == nullptr || (m = unmark (pt)) == 0)
+ uint8_t mk;
+ if (pt == nullptr || (mk = unmark (pt)) == 0)
continue;
match_complete (a, *pt);
// Nothing else to do if not marked for verification.
//
- if (m == 1)
+ if (mk == 1)
continue;
// Finish verifying the existing dependency (which is now matched)
@@ -2029,7 +2039,10 @@ namespace build2
for (prerequisite_member p1: group_prerequisite_members (a, *pt))
{
- if (p1.is_a (mod ? *x_mod : x_src) || p1.is_a<c> ())
+ if (mod
+ ? p1.is_a (*x_mod)
+ : (p1.is_a (x_src) || p1.is_a<c> () ||
+ (x_obj != nullptr && (p1.is_a (*x_obj) || p1.is_a<m> ()))))
{
// Searching our own prerequisite is ok, p1 must already be
// resolved.
diff --git a/libbuild2/cc/module.cxx b/libbuild2/cc/module.cxx
index 9063ebc..aa9a526 100644
--- a/libbuild2/cc/module.cxx
+++ b/libbuild2/cc/module.cxx
@@ -962,6 +962,9 @@ namespace build2
{
using namespace install;
+ // Note: not registering x_obj (it's registered seperately by the
+ // x.objx module).
+ //
rs.insert_target_type (x_src);
auto insert_hdr = [&rs, install_loaded] (const target_type& tt)
diff --git a/libbuild2/cc/target.cxx b/libbuild2/cc/target.cxx
index 3f71eb1..d743752 100644
--- a/libbuild2/cc/target.cxx
+++ b/libbuild2/cc/target.cxx
@@ -25,7 +25,6 @@ namespace build2
};
extern const char h_ext_def[] = "h";
-
const target_type h::static_type
{
"h",
@@ -40,7 +39,6 @@ namespace build2
};
extern const char c_ext_def[] = "c";
-
const target_type c::static_type
{
"c",
@@ -54,8 +52,21 @@ namespace build2
target_type::flag::none
};
- extern const char pc_ext[] = "pc"; // VC14 rejects constexpr.
+ extern const char m_ext_def[] = "m";
+ const target_type m::static_type
+ {
+ "m",
+ &cc::static_type,
+ &target_factory<m>,
+ nullptr, /* fixed_extension */
+ &target_extension_var<m_ext_def>,
+ &target_pattern_var<m_ext_def>,
+ nullptr,
+ &file_search,
+ target_type::flag::none
+ };
+ extern const char pc_ext[] = "pc"; // VC14 rejects constexpr.
const target_type pc::static_type
{
"pc",
@@ -70,7 +81,6 @@ namespace build2
};
extern const char pca_ext[] = "static.pc"; // VC14 rejects constexpr.
-
const target_type pca::static_type
{
"pca",
@@ -85,7 +95,6 @@ namespace build2
};
extern const char pcs_ext[] = "shared.pc"; // VC14 rejects constexpr.
-
const target_type pcs::static_type
{
"pcs",
diff --git a/libbuild2/cc/target.hxx b/libbuild2/cc/target.hxx
index fbac790..87df326 100644
--- a/libbuild2/cc/target.hxx
+++ b/libbuild2/cc/target.hxx
@@ -68,6 +68,22 @@ namespace build2
static const target_type static_type;
};
+ // Objective-C source file (the same rationale for having it here as for
+ // c{} above).
+ //
+ class LIBBUILD2_CC_SYMEXPORT m: public cc
+ {
+ public:
+ m (context& c, dir_path d, dir_path o, string n)
+ : cc (c, move (d), move (o), move (n))
+ {
+ dynamic_type = &static_type;
+ }
+
+ public:
+ static const target_type static_type;
+ };
+
// pkg-config file targets.
//
class LIBBUILD2_CC_SYMEXPORT pc: public file // .pc (common)