Add -namespace option to use unique prefix for all wrappers
Using this option allows to prefix all exported symbols (functions, enums and enum elements) with a prefix based on the given namespace. Note that (global) variables can't be exported directly when using the global namespace prefix, even if they are of C-compatible type.
This commit is contained in:
parent
54af856d09
commit
6833ead6ed
2 changed files with 75 additions and 16 deletions
|
|
@ -132,6 +132,11 @@ $ swig -c -help
|
|||
<th>C specific options</th>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>-namespace <nspace></td>
|
||||
<td>Generate wrappers with the prefix based on the provided namespace, e.g. if the option value is <tt>outer::inner</tt>, the prefix <tt>outer_inner_</tt> will be used. Notice that this is different from using SWIG <tt>nspace</tt> feature, as it applies the the prefix to all the symbols, regardless of the namespace they were actually declared in. Notably, this allows to export instantiations of templates defined in the <tt>std</tt> namespace, such as <tt>std::vector</tt>, using a custom prefix rather than <tt>std_</tt>.</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>-noexcept</td>
|
||||
<td>generate wrappers with no support of exception handling; see <a href="#C_exceptions">Exceptions</a> chapter for more details </td>
|
||||
|
|
|
|||
|
|
@ -178,6 +178,9 @@ class C:public Language {
|
|||
|
||||
String *empty_string;
|
||||
|
||||
// Prefix used for all symbols, if defined.
|
||||
String *ns_prefix;
|
||||
|
||||
// Prefix for module-level symbols, currently just the module name.
|
||||
String *module_prefix;
|
||||
|
||||
|
|
@ -201,12 +204,14 @@ public:
|
|||
|
||||
C() :
|
||||
empty_string(NewString("")),
|
||||
ns_prefix(NULL),
|
||||
module_prefix(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
~C()
|
||||
{
|
||||
Delete(ns_prefix);
|
||||
Delete(module_prefix);
|
||||
}
|
||||
|
||||
|
|
@ -226,6 +231,8 @@ public:
|
|||
if (nspace) {
|
||||
scoped_dohptr nspace_mangled(Swig_string_mangle(nspace));
|
||||
proxyname = NewStringf("%s_%s", (DOH*)nspace_mangled, symname);
|
||||
} else if (ns_prefix) {
|
||||
proxyname = NewStringf("%s_%s", ns_prefix, symname);
|
||||
} else {
|
||||
proxyname = Copy(symname);
|
||||
}
|
||||
|
|
@ -247,6 +254,15 @@ public:
|
|||
return wname;
|
||||
}
|
||||
|
||||
// Static member functions (which do have "c:globalfun" attribute) are a special case: normally we wouldn't want to use prefix for them neither, as they
|
||||
// already use the class name as prefix, but without one, they conflict with the names created by %extend, that use the same "class_method" form,
|
||||
// internally. So we still need to append some prefix to them, but we may avoid doing it if use a global prefix, as this is enough to avoid the conflict
|
||||
// with %extend, and doing this allows to avoid duplicating this prefix (as it is also part of the class name).
|
||||
if (Checkattr(n, "ismember", "1") && ns_prefix) {
|
||||
wname.assign_non_owned(name);
|
||||
return wname;
|
||||
}
|
||||
|
||||
// Use namespace as the prefix if feature:nspace is in use.
|
||||
scoped_dohptr scopename_prefix;
|
||||
if (GetFlag(parentNode(n), "feature:nspace")) {
|
||||
|
|
@ -257,11 +273,15 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
// Fall back to the module name if we don't use feature:nspace or are outside of any namespace.
|
||||
// Fall back to the module name if we don't use feature:nspace and don't have the global prefix neither.
|
||||
//
|
||||
// Note that we really, really need to use some prefix, as a global wrapper function can't have the same name as the original function (being wrapped) with
|
||||
// the same name.
|
||||
String* const prefix = scopename_prefix ? scopename_prefix : module_prefix;
|
||||
String* const prefix = scopename_prefix
|
||||
? scopename_prefix
|
||||
: ns_prefix
|
||||
? ns_prefix
|
||||
: module_prefix;
|
||||
|
||||
wname.assign_owned(NewStringf("%s_%s", prefix, name));
|
||||
return wname;
|
||||
|
|
@ -434,6 +454,16 @@ public:
|
|||
if (argv[i]) {
|
||||
if (strcmp(argv[i], "-help") == 0) {
|
||||
Printf(stdout, "%s\n", usage);
|
||||
} else if (strcmp(argv[i], "-namespace") == 0) {
|
||||
if (argv[i + 1]) {
|
||||
scoped_dohptr ns(NewString(argv[i + 1]));
|
||||
ns_prefix = Swig_string_mangle(ns);
|
||||
Swig_mark_arg(i);
|
||||
Swig_mark_arg(i + 1);
|
||||
i++;
|
||||
} else {
|
||||
Swig_arg_error();
|
||||
}
|
||||
} else if (strcmp(argv[i], "-noexcept") == 0) {
|
||||
except_flag = false;
|
||||
Swig_mark_arg(i);
|
||||
|
|
@ -454,13 +484,21 @@ public:
|
|||
SWIG_typemap_lang("c");
|
||||
SWIG_config_file("c.swg");
|
||||
|
||||
String* const ns_prefix_ = ns_prefix ? NewStringf("%s_", ns_prefix) : NewString("");
|
||||
|
||||
// The default naming convention is to use new_Foo(), copy_Foo() and delete_Foo() for the default/copy ctor and dtor of the class Foo, but we prefer to
|
||||
// start all Foo methods with the same prefix, so change this. Notice that new/delete are chosen to ensure that we avoid conflicts with the existing class
|
||||
// methods, more natural create/destroy, for example, could result in errors if the class already had a method with the same name, but this is impossible
|
||||
// for the chosen names as they're keywords in C++ ("copy" is still a problem but we'll just have to live with it).
|
||||
Swig_name_register("construct", "%n%c_new");
|
||||
Swig_name_register("copy", "%n%c_copy");
|
||||
Swig_name_register("destroy", "%n%c_delete");
|
||||
Swig_name_register("construct", NewStringf("%s%%n%%c_new", ns_prefix_));
|
||||
Swig_name_register("copy", NewStringf("%s%%n%%c_copy", ns_prefix_));
|
||||
Swig_name_register("destroy", NewStringf("%s%%n%%c_delete", ns_prefix_));
|
||||
|
||||
// These ones are only needed when using a global prefix, as otherwise the defaults are fine.
|
||||
if (ns_prefix) {
|
||||
Swig_name_register("member", NewStringf("%s%%n%%c_%%m", ns_prefix_));
|
||||
Swig_name_register("type", NewStringf("%s%%c", ns_prefix_));
|
||||
}
|
||||
|
||||
allow_overloading();
|
||||
}
|
||||
|
|
@ -587,21 +625,33 @@ public:
|
|||
if (Checkattr(n, "storage", "static"))
|
||||
return SWIG_NOWRAP;
|
||||
|
||||
// We can't export variables defined inside namespaces to C directly, whatever their type.
|
||||
String* const scope = Swig_scopename_prefix(Getattr(n, "name"));
|
||||
if (!scope) {
|
||||
// We can't export variables defined inside namespaces to C directly, whatever their type, and we can only export them under their original name, so we
|
||||
// can't do it when using a global namespace prefix neither.
|
||||
if (!ns_prefix && !scoped_dohptr(Swig_scopename_prefix(Getattr(n, "name")))) {
|
||||
// If we can export the variable directly, do it, this will be more convenient to use from C code than accessor functions.
|
||||
if (String* const var_decl = make_c_var_decl(n)) {
|
||||
Printv(f_wrappers_decl, "SWIGIMPORT ", var_decl, ";\n\n", NIL);
|
||||
Delete(var_decl);
|
||||
return SWIG_OK;
|
||||
}
|
||||
} else {
|
||||
Delete(scope);
|
||||
}
|
||||
|
||||
// We have to prepend the global prefix to the names of the accessors for this variable, if we use one.
|
||||
//
|
||||
// Note that we can't just register the name format using the prefix for "get" and "set", as we do it for "member", and using it for both would result in
|
||||
// the prefix being used twice for the member variables getters and setters, so we have to work around it here instead.
|
||||
if (ns_prefix && !getCurrentClass()) {
|
||||
Swig_require("c:globalvariableHandler", n, "*sym:name", NIL);
|
||||
Setattr(n, "sym:name", NewStringf("%s_%s", ns_prefix, Getattr(n, "sym:name")));
|
||||
}
|
||||
|
||||
// Otherwise, e.g. if it's of a C++-only type, or a reference, generate accessor functions for it.
|
||||
return Language::globalvariableHandler(n);
|
||||
int const rc = Language::globalvariableHandler(n);
|
||||
|
||||
if (Getattr(n, "view"))
|
||||
Swig_restore(n);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* -----------------------------------------------------------------------
|
||||
|
|
@ -1445,7 +1495,8 @@ public:
|
|||
return SWIG_NOWRAP;
|
||||
|
||||
// Preserve the typedef if we have it in the input.
|
||||
String* const tdname = Getattr(n, "tdname");
|
||||
maybe_owned_dohptr tdname;
|
||||
tdname.assign_non_owned(Getattr(n, "tdname"));
|
||||
if (tdname) {
|
||||
Printv(f_wrappers_types, "typedef ", NIL);
|
||||
}
|
||||
|
|
@ -1454,7 +1505,11 @@ public:
|
|||
if (Node* const klass = getCurrentClass()) {
|
||||
enum_prefix = getProxyName(klass);
|
||||
} else {
|
||||
enum_prefix = NIL;
|
||||
enum_prefix = ns_prefix; // Possibly NULL, but that's fine.
|
||||
}
|
||||
|
||||
if (tdname && enum_prefix) {
|
||||
tdname.assign_owned(NewStringf("%s_%s", enum_prefix, tdname.get()));
|
||||
}
|
||||
|
||||
scoped_dohptr enumname;
|
||||
|
|
@ -1493,9 +1548,7 @@ public:
|
|||
enum_prefix = NULL;
|
||||
|
||||
if (tdname) {
|
||||
String* const enumname = Swig_name_mangle(tdname);
|
||||
Printv(f_wrappers_types, " ", enumname, NIL);
|
||||
Delete(enumname);
|
||||
Printv(f_wrappers_types, " ", tdname.get(), NIL);
|
||||
}
|
||||
Printv(f_wrappers_types, ";\n\n", NIL);
|
||||
|
||||
|
|
@ -1619,6 +1672,7 @@ extern "C" Language *swig_c(void) {
|
|||
|
||||
const char *C::usage = (char *) "\
|
||||
C Options (available with -c)\n\
|
||||
-namespace ns - use prefix based on the provided namespace\n\
|
||||
-noexcept - do not generate exception handling code\n\
|
||||
\n";
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue