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>
|
<th>C specific options</th>
|
||||||
</tr>
|
</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>
|
<tr>
|
||||||
<td>-noexcept</td>
|
<td>-noexcept</td>
|
||||||
<td>generate wrappers with no support of exception handling; see <a href="#C_exceptions">Exceptions</a> chapter for more details </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;
|
String *empty_string;
|
||||||
|
|
||||||
|
// Prefix used for all symbols, if defined.
|
||||||
|
String *ns_prefix;
|
||||||
|
|
||||||
// Prefix for module-level symbols, currently just the module name.
|
// Prefix for module-level symbols, currently just the module name.
|
||||||
String *module_prefix;
|
String *module_prefix;
|
||||||
|
|
||||||
|
|
@ -201,12 +204,14 @@ public:
|
||||||
|
|
||||||
C() :
|
C() :
|
||||||
empty_string(NewString("")),
|
empty_string(NewString("")),
|
||||||
|
ns_prefix(NULL),
|
||||||
module_prefix(NULL)
|
module_prefix(NULL)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
~C()
|
~C()
|
||||||
{
|
{
|
||||||
|
Delete(ns_prefix);
|
||||||
Delete(module_prefix);
|
Delete(module_prefix);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -226,6 +231,8 @@ public:
|
||||||
if (nspace) {
|
if (nspace) {
|
||||||
scoped_dohptr nspace_mangled(Swig_string_mangle(nspace));
|
scoped_dohptr nspace_mangled(Swig_string_mangle(nspace));
|
||||||
proxyname = NewStringf("%s_%s", (DOH*)nspace_mangled, symname);
|
proxyname = NewStringf("%s_%s", (DOH*)nspace_mangled, symname);
|
||||||
|
} else if (ns_prefix) {
|
||||||
|
proxyname = NewStringf("%s_%s", ns_prefix, symname);
|
||||||
} else {
|
} else {
|
||||||
proxyname = Copy(symname);
|
proxyname = Copy(symname);
|
||||||
}
|
}
|
||||||
|
|
@ -247,6 +254,15 @@ public:
|
||||||
return wname;
|
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.
|
// Use namespace as the prefix if feature:nspace is in use.
|
||||||
scoped_dohptr scopename_prefix;
|
scoped_dohptr scopename_prefix;
|
||||||
if (GetFlag(parentNode(n), "feature:nspace")) {
|
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
|
// 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.
|
// 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));
|
wname.assign_owned(NewStringf("%s_%s", prefix, name));
|
||||||
return wname;
|
return wname;
|
||||||
|
|
@ -434,6 +454,16 @@ public:
|
||||||
if (argv[i]) {
|
if (argv[i]) {
|
||||||
if (strcmp(argv[i], "-help") == 0) {
|
if (strcmp(argv[i], "-help") == 0) {
|
||||||
Printf(stdout, "%s\n", usage);
|
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) {
|
} else if (strcmp(argv[i], "-noexcept") == 0) {
|
||||||
except_flag = false;
|
except_flag = false;
|
||||||
Swig_mark_arg(i);
|
Swig_mark_arg(i);
|
||||||
|
|
@ -454,13 +484,21 @@ public:
|
||||||
SWIG_typemap_lang("c");
|
SWIG_typemap_lang("c");
|
||||||
SWIG_config_file("c.swg");
|
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
|
// 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
|
// 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
|
// 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).
|
// 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("construct", NewStringf("%s%%n%%c_new", ns_prefix_));
|
||||||
Swig_name_register("copy", "%n%c_copy");
|
Swig_name_register("copy", NewStringf("%s%%n%%c_copy", ns_prefix_));
|
||||||
Swig_name_register("destroy", "%n%c_delete");
|
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();
|
allow_overloading();
|
||||||
}
|
}
|
||||||
|
|
@ -587,21 +625,33 @@ public:
|
||||||
if (Checkattr(n, "storage", "static"))
|
if (Checkattr(n, "storage", "static"))
|
||||||
return SWIG_NOWRAP;
|
return SWIG_NOWRAP;
|
||||||
|
|
||||||
// We can't export variables defined inside namespaces to C directly, whatever their type.
|
// 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
|
||||||
String* const scope = Swig_scopename_prefix(Getattr(n, "name"));
|
// can't do it when using a global namespace prefix neither.
|
||||||
if (!scope) {
|
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 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)) {
|
if (String* const var_decl = make_c_var_decl(n)) {
|
||||||
Printv(f_wrappers_decl, "SWIGIMPORT ", var_decl, ";\n\n", NIL);
|
Printv(f_wrappers_decl, "SWIGIMPORT ", var_decl, ";\n\n", NIL);
|
||||||
Delete(var_decl);
|
Delete(var_decl);
|
||||||
return SWIG_OK;
|
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.
|
// 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;
|
return SWIG_NOWRAP;
|
||||||
|
|
||||||
// Preserve the typedef if we have it in the input.
|
// 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) {
|
if (tdname) {
|
||||||
Printv(f_wrappers_types, "typedef ", NIL);
|
Printv(f_wrappers_types, "typedef ", NIL);
|
||||||
}
|
}
|
||||||
|
|
@ -1454,7 +1505,11 @@ public:
|
||||||
if (Node* const klass = getCurrentClass()) {
|
if (Node* const klass = getCurrentClass()) {
|
||||||
enum_prefix = getProxyName(klass);
|
enum_prefix = getProxyName(klass);
|
||||||
} else {
|
} 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;
|
scoped_dohptr enumname;
|
||||||
|
|
@ -1493,9 +1548,7 @@ public:
|
||||||
enum_prefix = NULL;
|
enum_prefix = NULL;
|
||||||
|
|
||||||
if (tdname) {
|
if (tdname) {
|
||||||
String* const enumname = Swig_name_mangle(tdname);
|
Printv(f_wrappers_types, " ", tdname.get(), NIL);
|
||||||
Printv(f_wrappers_types, " ", enumname, NIL);
|
|
||||||
Delete(enumname);
|
|
||||||
}
|
}
|
||||||
Printv(f_wrappers_types, ";\n\n", NIL);
|
Printv(f_wrappers_types, ";\n\n", NIL);
|
||||||
|
|
||||||
|
|
@ -1619,6 +1672,7 @@ extern "C" Language *swig_c(void) {
|
||||||
|
|
||||||
const char *C::usage = (char *) "\
|
const char *C::usage = (char *) "\
|
||||||
C Options (available with -c)\n\
|
C Options (available with -c)\n\
|
||||||
|
-namespace ns - use prefix based on the provided namespace\n\
|
||||||
-noexcept - do not generate exception handling code\n\
|
-noexcept - do not generate exception handling code\n\
|
||||||
\n";
|
\n";
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue