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

Suppose I have a title, for example #include <GL/gl.h> . It contains a subset of the 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 expands to a pointer to glDrawArraysIndirect, if it is defined, or for the stub function stub_glDrawArraysIndirect otherwise.

My target operating system is very specific. Any linker-based solution (e.g. GetProcAddress or dlsym ) does not work for me since there is no dynamic linker. Moreover, my driver does not provide glXGetProcAdrress and wglGetProcAddress , basically there is no way to request a pointer at runtime by function name (in fact, I want to implement such a mechanism).

Any ideas?

+5
source share
4 answers

Here is an answer that can detect it at compile time and create a boolean. It works by creating a template function with the same name in the namespace, and then using that namespace inside the is_defined() function. If real glDrawArraysIndirect() exists, it will give preference to the pattern. If you comment out the first glDrawArraysIndirect() declaration, a static statement below will be triggered.

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 tweaking, you can make your custom function a 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); } 
+5
source

Include the expression sizeof(::function) somewhere. (If the function exists, then asking for the size of the function pointer is the right thing).

It will be benign at runtime, and :: forces you to use a function declared in the global scope.

Of course, if function does not exist in the global scope, then compilation will fail.

Along with other errors, the compiler will throw a certain error if you have to write something in the lines

static_assert(sizeof(::function), "There is no global function");

+2
source

My target operating system is very specific. Any linker-based solution (e.g. GetProcAddress or dlsym) does not work for me as there is no dynamic linker.

Is it an embedded system or just a weird stripped down OS running on a standard PC?

More than my driver does not provide glXGetProcAdrress or wglGetProcAddress, in principle there is no way to request a pointer at runtime by function name

The attribute for querying function pointers at run time is independent of the presence of a dynamic linker. The two are completely orthogonal, and even a fully statically linked embedded OpenGL implementation can offer the GetProcAddress interface just fine. Instead of somehow solving the problem during compilation or linking, I would rather solve the problem by doing GetProcAddress for your OpenGL driver; you can do this even if the driver is available as a static library in binary form. Step one:

Create function pointer stubs for each OpenGL function statically initialized to NULL and attributed to weak coupling. Link this in a static library, which you can call gl_null_stubs or similar.

Create a GetProcAddress function that for each OpenGL function returns a pointer to a function symbol within the compilation area of ​​the function.

Now link your weird OpenGL driver to the stub library and the GetProcAddress implementation. For each function, there is a weak connection stub so that the symbol of the static library takes precedence. For all OpenGL characters not included in your driver, stubs will be enabled.

There: you now have an OpenGL driver library with the implementation of GetProcAddress. It wasn’t that hard, was it?

+1
source

How to check if a function is declared in the global scope at compile time? My target operating system is very specific ...

A possible solution may be if you use the recent GCC - perhaps as a cross-compiler for your strange target OS and ABI- to configure the gcc compiler (or g++ , etc.) using the native MELT extension.

MELT is a domain-specific language implemented as a GCC plugin for free software (mainly on Linux) to configure the GCC compiler.

+1
source

Source: https://habr.com/ru/post/1244892/


All Articles