Checking if a function has C-linkage at compile-time [unsolvable] - c++

Is there any way to check if a given function is declared with C-linkage (that is, with extern "C") at compile-time?
I am developing a plugin system. Each plugin can supply factory functions to the plugin-loading code. However, this has to be done via name (and subsequent use of GetProcAddress or dlsym). This requires that the functions be declared with C-linkage so as to prevent name-mangling. It would be nice to be able to throw a compiler error if the referred-to function is declared with C++-linkage (as opposed to finding out at runtime when a function with that name does not exist).
Here's a simplified example of what I mean:
extern "C" void my_func()
{
}
void my_other_func()
{
}
// Replace this struct with one that actually works
template<typename T>
struct is_c_linkage
{
static const bool value = true;
};
template<typename T>
void assertCLinkage(T *func)
{
static_assert(is_c_linkage<T>::value, "Supplied function does not have C-linkage");
}
int main()
{
assertCLinkage(my_func); // Should compile
assertCLinkage(my_other_func); // Should NOT compile
}
Is there a possible implementation of is_c_linkage that would throw a compiler error for the second function, but not the first? I'm not sure that it's possible (though it may exist as a compiler extension, which I'd still like to know of). Thanks.

I agree with Jonathan Leffler that this probably is not possible in a standard way. Maybe it would be possible somewhat, depending on the compiler and even version of the compiler, but you would have to experiment to determine possible approaches and accept the fact that the compiler's behavior was likely unintentional and might be "fixed" in later versions.
With g++ version 4.4.4 on Debian Squeeze, for example, you might be able to raise a compiler error for functions that are not stdcall with this approach:
void my_func() __attribute__((stdcall));
void my_func() { }
void my_other_func() { }
template <typename ret_, typename... args_>
struct stdcall_fun_t
{
typedef ret_ (*type)(args_...) __attribute__((stdcall));
};
int main()
{
stdcall_fun_t<void>::type pFn(&my_func),
pFn2(&my_other_func);
}
g++ -std=c++0x fails to compile this code because:
SO2936360.cpp:17: error: invalid conversion from ‘void ()()’ to ‘void ()()’
Line 17 is the declaration of pFn2. If I get rid of this declaration, then compilation succeeds.
Unfortunately, this technique does not work with cdecl.

For Unix/Linux, how about analyzing the resulting binary with 'nm' and looking for symbol names? I suppose it's not what you meant, but still it's sort of compile time.

Related

g++ std::visit leaking into global namespace?

I just bounced into something subtle in the vicinity of std::visit and std::function that baffles me. I'm not alone, but the only other folks I could find did the "workaround and move on" dance, and that's not enough for me:
https://github.com/fmtlib/fmt/issues/851
https://github.com/jamboree/bustache/issues/11
This may be related to an open issue in the LWG, but I think something more sinister is happening here:
https://cplusplus.github.io/LWG/issue3052
Minimal Example:
// workaround 1: don't include <variant>
#include <variant>
#include <functional>
struct Target
{
Target *next = nullptr;
};
struct Visitor
{
void operator()(const Target &tt) const { }
};
// workaround 2: concretely use 'const Visitor &' instead of 'std::function<...>'
void visit(const Target &target, const std::function<void(const Target &)> &visitor)
{
visitor(target);
if(target.next)
visit(*target.next,visitor); // workaround 3: explicitly invoke ::visit(...)
//^^^ problem: compiler is trying to resolve this as std::visit(...)
}
int main(int argc, char **argv, char **envp)
{
return 0;
}
Compile with g++ -std=c++17, tested using:
g++-7 (Ubuntu 7.5.0-3ubuntu1~18.04)
g++-8 (Ubuntu 8.4.0-1ubuntu1~18.04)
The net result is the compiler tries to use std::visit for the clearly-not-std invocation of visit(*target.next,visitor):
g++-8 -std=c++17 -o wtvariant wtvariant.cpp
In file included from sneakyvisitor.cpp:3:
/usr/include/c++/8/variant: In instantiation of ‘constexpr decltype(auto) std::visit(_Visitor&&, _Variants&& ...) [with _Visitor = Target&; _Variants = {const std::function<void(const Target&)>&}]’:
wtvariant.cpp:20:31: required from here
/usr/include/c++/8/variant:1385:23: error: ‘const class std::function<void(const Target&)>’ has no member named ‘valueless_by_exception’
if ((__variants.valueless_by_exception() || ...))
~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~
/usr/include/c++/8/variant:1390:17: error: no matching function for call to ‘get<0>(const std::function<void(const Target&)>&)’
std::get<0>(std::forward<_Variants>(__variants))...));
~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
In my real use case, I thought someone had snuck a "using namespace std" into the header space of my tree and I was gonna be grumpy. However, this minimal example demonstrates otherwise.
Critical Question: given that I have not created nor used any namespaces, why is std::visit(...) getting involved here at all?
WRT workaround 1: At least in the variant header, visit(...) is declared properly in the std namespace
WRT workaround 2: If the second argument is anything other than a std::function, it compiles just fine, leading me to believe that something more subtle is going on here.
WRT workaround 3: I understand that two colons are a small price to pay, but that they are necessary at all feels dangerous to me given my expectations for what it means to put a free function like visit(...) into a namespace.
Any one of the three marked workarounds will suppress the compiler error, but I'm personally intolerant of language glitches that I can't wrap my head around (Though I understand the necessity, I'm still uneasy about how often I have to sprinkle 'typename' into templates to make them compile).
Also of note, if try to make use of other elements of the std namespace without qualification (e.g., try a naked 'cout'), the compiler properly grumps about not being able to figure out the 'cout' that I'm after, so it's not as though the variant header is somehow flattening the std namespace.
Lastly, this problem persists even if I put my visit() method in its own namespace: the compiler really wants to use std::visit(...) unless I explicitly invoke my_namespace::visit(...).
What am I missing?
The argument visitor is an std::function, which is in the namespace std, so argument-dependent lookup finds visit in the namespace std as well.
If you always want the visit in the global namespace, say so with ::visit.

How to check if function is declared in global scope at compile time

Let I have a header, for example #include <GL/gl.h>. It contains subset of OpenGL API functions. I need something like this:
static_assert(has_glDrawArraysIndirect::value, "There is no glDrawArraysIndirect");
Or even better:
PFNGLDRAWARRAYSINSTANCEDPROC ptr_glDrawArraysIndirect = ptr_to_glDrawArraysIndirect::ptr;
Where ptr_to_glDrawArraysIndirect::ptr unrolls to pointer to glDrawArraysIndirect if it's defined or to a stub function stub_glDrawArraysIndirect otherwise.
My target operating system is very specific. Any linker based solution (like GetProcAddress or dlsym) doesn't work for me, since there is no dynamic linker. More than, my driver doesn't provide glXGetProcAdrress nor wglGetProcAddress, basically there there is no way to query pointer at run time by function name (Actually, I want to implement such a mechanism).
Any ideas?
Here is an answer that can detect it at compile time and produce a boolean value. It works by creating a template function of the same name in a namespace and then using that namespace inside of the is_defined() function. If the real glDrawArraysIndirect() exists it will take preference over the template version. If you comment out the first declaration of glDrawArraysIndirect() the static assert at the bottom will trigger.
Test on GodBolt
#include <type_traits>
enum GLenum {};
void glDrawArraysIndirect(GLenum, const void*);
namespace detail {
struct dummy;
template<typename T>
dummy& glDrawArraysIndirect(T, const void*);
}
constexpr bool is_defined()
{
using namespace detail;
using ftype = decltype(glDrawArraysIndirect(GLenum(), nullptr));
return std::is_same<ftype, void>();
}
static_assert(is_defined(), "not defined");
With a little tweak you can make your custom function the template and use a similar trick
ideone.com
#include <type_traits>
#include <iostream>
//#define USE_REAL
enum GLenum {TEST};
typedef void (*func_type)(GLenum, const void*);
#ifdef USE_REAL
void glDrawArraysIndirect(GLenum, const void*);
#endif
namespace detail {
struct dummy {};
template<typename T = dummy>
void glDrawArraysIndirect(GLenum, const void*, T = T())
{
std::cout << "In placeholder function" << std::endl;
}
}
void wrapDraw(GLenum x, const void* y)
{
using namespace detail;
glDrawArraysIndirect(x, y);
}
#ifdef USE_REAL
void glDrawArraysIndirect(GLenum, const void*)
{
std::cout << "In real function" << std::endl;
}
#endif
int main()
{
wrapDraw(TEST, nullptr);
}
Include the expression sizeof(::function) somewhere. (If the function exists then asking for the size of the pointer to the function is a perfectly valid thing to do).
It will be benign at runtime, and :: forces the use of the function declared at global scope.
Of course, if function does not exist at global scope, then compilation will fail.
Along with other errors, the compiler will issue a specific error if you were to write something on the lines of
static_assert(sizeof(::function), "There is no global function");
My target operating system is very specific. Any linker based solution (like GetProcAddress or dlsym) doesn't work for me, since there is no dynamic linker.
Is this an embedded system or just a weirdly stripped down OS running on standard PC hardware?
More than, my driver doesn't provide glXGetProcAdrress nor wglGetProcAddress, basically there there is no way to query pointer at run time by function name
The abiliy to query function pointers at runtime does not depend on the presence of a dynamic linker. Those two are completely orthogonal and even a purely statically linked embedded OpenGL implementation can offer a GetProcAddress interface just fine. Instead of trying to somehow solve the problem at compile or link time, I'd rather address the problem by implementing a GetProcAddress for your OpenGL driver; you can do that even if the driver is available as only a static library in binary form. Step one:
Create function pointer stubs for each and every OpenGL function, statically initialized to NULL and attributed weak linkage. Link this into a static library you may call gl_null_stubs or similar.
Create a GetProcAddress function that for every OpenGL function there is returns the pointer to the function symbol within the scope of the function's compilation unit.
Now link your weird OpenGL driver with the stubs library and the GetProcAddress implementation. For every function there is, the weak linkage of the stub will the static library symbol to take precedence. For all OpenGL symbols not in your driver the stubs will take over.
There: Now you have a OpenGL driver library that has a GetProcAddress implementation. That wasn't that hard, was it?
How to check if function is declared in global scope at compile time?
My target operating system is very specific...
A possible solution might be, if you are using a recent GCC -probably as a cross-compiler for your weird target OS and ABI- to customize the gcc (or g++ etc...) compiler with your own MELT extension.
MELT is a domain specific language, implemented as a free software GCC plugin (mostly on Linux), to customize the GCC compiler.

Is there any way to check whether a function has been declared?

Suppose there's a library, one version of which defines a function with name foo, and another version has the name changed to foo_other, but both these functions still have the same arguments and return values. I currently use conditional compilation like this:
#include <foo.h>
#ifdef USE_NEW_FOO
#define trueFoo foo_other
#else
#define trueFoo foo
#endif
But this requires some external detection of the library version and setting the corresponding compiler option like -DUSE_NEW_FOO. I'd rather have the code automatically figure what function it should call, based on it being declared or not in <foo.h>.
Is there any way to achieve this in any version of C?
If not, will switching to any version of C++ provide me any ways to do this? (assuming the library does all the needed actions like extern "C" blocks in its headers)? Namely, I'm thinking of somehow making use of SFINAE, but for a global function, rather than method, which was discussed in the linked question.
In C++ you can use expression SFINAE for this:
//this template only enabled if foo is declared with the right args
template <typename... Args>
auto trueFoo (Args&&... args) -> decltype(foo(std::forward<Args>(args)...))
{
return foo(std::forward<Args>(args)...);
}
//ditto for fooOther
template <typename... Args>
auto trueFoo (Args&&... args) -> decltype(fooOther(std::forward<Args>(args)...))
{
return fooOther(std::forward<Args>(args)...);
}
If you are statically linking to a function, in most versions of C++, the name of the function is "mangled" to reflect its argument list. Therefore, an attempt to statically link to the library, by a program with an out-of-date .hpp file, will result in an "unknown symbol" linker-error.
In the C language, there's no metadata of any kind which indicates what the argument list of any exported function actually is.
Realistically, I think, you simply need to be sure that the .h or .hpp files that you're using to link to a library, actually reflect the corresponding object-code within whatever version of that library you are using. You also need to be sure that the Makefile (or "auto-make" process) will correctly identify any-and-all modules within your application which link-to that library and which therefore must be recompiled in case of any changes to it. (If it were me, I would recompile the entire application.) In short, you must see to it that this issue doesn't occur.
In C++ you can do something like this:
#include <iostream>
#include <type_traits>
//#define DEFINE_F
#ifdef DEFINE_F
void f()
{
}
#endif
namespace
{
constexpr struct special
{
std::false_type operator()() const;
}f;
}
struct checkForF
{
static const constexpr auto value = std::conditional< std::is_same<std::false_type, decltype(::f())>::value, std::false_type, std::true_type >::type();
};
int main()
{
std::cout << checkForF::value << std::endl;
}
ideone
Please note I only handle f without any parameters.

Can't get warnings to work for header-only library

I'm creating an header-only library, and I would like to get warnings for it displayed during compilation. However, it seems that only warnings for the "main" project including the library get displayed, but not for the library itself.
Is there a way I can force the compiler to check for warnings in the included library?
// main.cpp
#include "MyHeaderOnlyLib.hpp"
int main() { ... }
// Compile
g++ ./main.cpp -Wall -Wextra -pedantic ...
// Warnings get displayed for main.cpp, but not for MyHeaderOnlyLib.hpp
I'm finding MyHeaderOnlyLib.hpp via a CMake script, using find_package. I've checked the command executed by CMake, and it's using -I, not -isystem.
I've tried both including the library with <...> (when it's in the /usr/include/ directory), or locally with "...".
I suppose that you have a template library and you are complaining about the lack of warnings from its compilation. Don't look for bad #include path, that would end up as an error. Unfortunately, without specialization (unless the templates are used by the .cpp), the compiler has no way to interpret the templates reliably, let alone produce sensible warnings. Consider this:
#include <vector>
template <class C>
struct T {
bool pub_x(const std::vector<int> &v, int i)
{
return v.size() < i;
}
bool pub_y(const std::vector<int> &v, int i)
{
return v.size() < i;
}
};
typedef T<int> Tint; // will not help
bool pub_z(const std::vector<int> &v, unsigned int i) // if signed, produces warning
{
return v.size() < i;
}
class WarningMachine {
WarningMachine() // note that this is private
{
//T<int>().pub_y(std::vector<int>(), 10); // to produce warning for the template
}
};
int main()
{
//Tint().pub_y(std::vector<int>(), 10); // to produce warning for the template
return 0;
}
You can try it out in codepad. Note that the pub_z will immediately produce signed / unsigned comparison warning when compiled, despite never being called. It is a whole different story for the templates, though. Even if T::pub_y is called, T::pub_x still passes unnoticed without a warning. This depends on a compiler implementation, some compilers perform more aggressive checking once all the information is available, other tend to be lazy. Note that neither T::pub_x or T::pub_y depend on the template argument.
The only way to do it reliably is to specialize the templates and call the functions. Note that the code which does that does not need to be accessible for that (such as in WarningMachine), making it a candidate to be optimized away (but that depends), and also meaning that the values passed to the functions may not need to be valid values as the code will never run (that will save you allocating arrays or preparing whatever data the functions may need).
On the other hand, since you will have to write a lot of code to really check all the functions, you may as well pass valid data and check for result correctness and make it useful, instead of likely confusing the hell of anyone who reads the code after you (as is likely in the above case).

Why can't I pass typedef or enum in Arduino?

The following sketch to fails to compile in the Arduino environment.
Given that typedefs can be used within Arduino software, is Automatic Prototype Generation the underlying mechanism that causes the failure? If so, what is it and why isn't Arduino providing a lightweight wrapper around C++?
#define PRODUCE_WACKY_COMPILETIME_ERROR
typedef int MyMeaningfulType;
#ifndef PRODUCE_WACKY_COMPILETIME_ERROR
void myFunc(MyMeaningfulType myParam);
#endif
void myFunc(MyMeaningfulType myParam)
{
myFunc(10);
}
void setup() {}
void loop() {}
For the benefit of the search engines, the errors reported are:
error: variable or field 'myFunc' declared void
error: 'MyMeaningfulType' was not declared in this scope
Please refer to http://arduino.cc/en/Hacking/BuildProcess the specific quote is:
This means that if you want to use a custom type as a function argument, you should declare it within a separate header file.
This page does a good job of explaining how the Arduino Language is different from C/C++ in how it works/pre-processes files.
They are attempting to create prototypes for every function they find. Unfortunately, if you define a typedef in the file before the function, and use that in a function definition, the place they put the function prototype does not see it, and this generates a syntax error.
If you use the 'struct * ' syntax instead in those function definitions, you benefit from C's 'opaque type' facility, in which you can use a struct definition without having it be declared beforehand. So, build the typedef, use it, but use the struct definition in any functions that use the typedef in arguments.
typedef struct mytype_ {
int f1;
} mytype_t;
void myfunc(struct mytype_ * xxx) {
xxx->f1 = 1;
}