2

I have a tool-chain in which header files are generated (by javac -h, i.e. Java Native Interface), but the implementation of the functions is manually written. It would be really useful to get an error message when a supposed implementation function doesn’t actually implement a header-declared function (usually because the header function was updated).

I know how I would do that if the header functions were in a namespace:

#pragma once
namespace N
{
    void f();
}
#include "header.hpp"
void N::f() { }
// good: compile error when you change the declaration in the header!

The function defined by N::f() won’t compile without the declaration (in the header).

However, the generator doesn’t put stuff in namespaces (and I found no way to tell it to), so I tried the global namespace, but that is apparently not allowed:

#pragma once
void f();
#include "header.hpp"
void (::f)() { }
// error (on MSVC)
// warning "extra/explicit qualification on member 'f'" (on Clang/GCC)

I have to support MSVC, so suppressing the warning is not an option.

As a last resort, because all the functions are extern "C", I thought I could maybe wrap the #include "header.hpp" in a namespace, but that didn’t work either.

I’m out of ideas. Is this plain unsolvable?

Quirin F. Schroll
  • 1,302
  • 1
  • 11
  • 25
  • I’m on my phone now so I cannot test it, but shouldn’t taking the address of a declared yet undefined function trigger a linker error? – alagner Jun 22 '23 at 15:58
  • I don’t think that works. First, ideally, I want compile errors not link errors. Secondly, when I only look at the cpp file and arbitrarily take the address of functions defined there, they’re of course defined, irrespective of whether they’re declared in the header. – Quirin F. Schroll Jun 22 '23 at 16:02
  • AFAIK JNI is bridge into a C not C++, so namespaces are not available. Problem is C++ name mangling. – Marek R Jun 22 '23 at 16:28
  • The JNI header tests for `__cplusplus`, so it’s clearly C++ as well as C; if it can insert `extern "C"` conditionally, it can – in principle – insert a namespace. I use C++; if the solution is C++-only, I don’t care. – Quirin F. Schroll Jun 22 '23 at 16:44
  • `void ::f() {}` [is actually valid](https://wg21.link/CWG482) (and compiles on MSVC/clang), but a [gcc bug](https://gcc.gnu.org/bugzilla/show_bug.cgi?id=64267) makes this not compile on gcc so it's not that helpful if you need to support gcc. – Artyer Jun 22 '23 at 17:03

2 Answers2

3

You can at least get a warning with GCC or Clang by using the appropriate flag:

  • -Wmissing-declarations for GCC
  • -Wmissing-prototypes for Clang

Clang also provides -Wmissing-declarations but it does not do the same thing.

GCC also provides -Wmissing-prototypes but not for C++, I'm not sure why.

See also this question.

Nelfeal
  • 12,593
  • 1
  • 20
  • 39
1

I found a solution and it’s actually pretty, but rather hacky.

Simply putting the include of the generated header in a namespace doesn’t work:

namespace jni
{
#include "header.hpp"
}

The problems do not stem from what’s in header.hpp directly, but from what’s in jni.h that the generated header includes.

But, because jni.h has header protections, one can include jni.h in the implementation file before including the generated header!

#include <jni.h>
namespace jni
{
#include "header.hpp"
}

// Here, all the generated functions are in namespace jni.

Because all the generated functions are extern "C", for the JNI to call them, it doesn’t matter if C++ put them in namespaces. Because C has no namespace, in the object file, the namespaces are gone!

Quirin F. Schroll
  • 1,302
  • 1
  • 11
  • 25