How to handle 'Object': ambiguous symbol in Visual Studio - c++-cli

I am creating a C++/CLI wrapper for native C code that has it's own Object typedef and am receiving the C2872 'Object': ambiguous symbol error when linking. The compiler output is:
1>C:\src\OS_kernel.h(27): error C2872: 'Object': ambiguous symbol
1>C:\src\OS_types.h(261): note: could be 'ObjectStruct *Object'
1>C:\src\OS_kernel.h(27): note: or 'System::Object'
It may be worth mentioning that I am mocking this native C code for the purposes of the C++/CLI wrapper; not sure if that opens up a potential solution that would otherwise not be available if no source code was available. I'm guessing there is a way to specify which definition I want the code to use, but I don't know how to specify that. Is that possible? I want to specify it to use the ObjectStruct *Object.
It would be great if I didn't have to modify the mock code since it could potentially be hundreds or thousands of individual places.
As an aside, I am also receiving this error for other types the native library is using, such as Buffer and Boolean.

OK, since you're getting the error in OS_kernel.h, I'm guessing that's part of the C code you're wrapping.
Obviously, one possible solution is to treat the name Object as a reserved word, and edit your C code to not use it. One could argue that this is the most correct solution, but it may not be possible to do that.
Depending on how you're referencing the C code, it may be reasonable to compile it as C++, and stick it entirely within a namespace. That way, when the C code (now C++ code) uses Object it will see the typedef within its namespace, and you'll have the option to reference either namespace in your code.
The fact that you're getting this error from your library's header file indicates to me that you've got a using namespace System; directive, and that the #include of your library's header files comes after that using directive. Consider removing the using namespace System;, or at least moving it after the #include. This way, you won't get that error in the library's headers, you'll just have to deal with it in your code.

Related

Using void structs in Raku via NativeCall

I'm trying to link libzip to Raku, and it uses a void struct or a struct with no body, like this:
struct zip;
typedef struct zip zip_t;
I declare it in my Raku program in the same way:
class zip_t is repr('CStruct'){};
This fails with:
Class zip_t has no attributes, which is illegal with the CStruct representation.
Only reference I have found to that error is in this non-addressed issue in MyHTML. That might make it a regression, but I'm really not sure. Any idea?
A google for "no attributes, which is illegal with the CStruct representation" yields three matches. The third leads to the following recent bug/change for module LibZip:
- class zip is repr('CStruct') is export { }
+ class zip is repr('CPointer') is export { }
Before I publish this I see Curt Tilmes has commented to similar effect.
I know little about C. But I enjoy researching things. This answer is a guess and some notes based on googling.
The error message you've quoted is about NativeCall, which in turn means it's about the Rakudo compiler, not the Raku language. (I presume you know this, and for many folk and situations the distinction isn't typically important, but I think it worth noting in this case.)
The top SO match for a google for "empty struct" is Empty structs in C. The question asks about the semantics of empty structs and using them with a foreign language. The question and its answers seem useful; the next few points are based on excerpts from them.
"Structures with no named members [have undefined behavior]". I'd say this explains why you're getting the NativeCall error message ("no attributes, which is illegal with the CStruct representation".). NativeCall is about having a reliable portable interface to C so it presumably must summarily reject undefined aspects. (Perhaps the error message could hint at what to do instead? Probably not. It's probably better that someone must search for matches to the message, just as you have done. And then presumably they would see this SO.)
I presume you're just trying to bind with libzip's empty struct as part of passing data back and forth without reading or writing it. I suspect that that is the crux of the problem here; how do you bind given that NativeCall (quite reasonably) refuses to do it in the usual manner?
"From the point of view of writing [a foreign language] binding to a C library ... You're never going to do anything with objects of the [empty struct] type except pass them to imported C functions." I presume this is true for your situation and that anything else would be undefined behavior per the C spec and thus at least tied to a specific C compiler for both the C library and the C compiler used to compile Rakudo and quite possibly undefined even then. I presume Curt has asked about your usage in case the binding is doing or requiring something crazy, but I very much doubt that it is.

Is it possible to prevent POSIX symbol name pollution in Objective-C?

I've run into a somewhat unexpected behavior in Xcode/Objective-C. I know it's probably not advised, but if I want to make my own struct in_addr in a .m file, it seems I can't. This implies something rather strange about namespaces and symbol pollution in Objective-C. The same seems to apply for many other networking types and perhaps other POSIX-y things as well.
I came up with a very basic example that demonstrates this behavior. Note that this snippet is the entire contents of the .m file.
#define _SYS_SOCKET_H_
#define _NETINET_IN_H_
#include <stdint.h>
struct in_addr {
uint32_t foo;
};
which yields the build error Redefinition of 'in_addr'.
This implies some fairly strange things about Objective-C. For starters, I wouldn't expect <stdint.h> to bring in any networking types. But even allowing that it might, defining _NETINET_IN_H_ first should prevent the definition of struct in_addr. And yet even still, this code refuses to build.
Is it possible to somehow forgo this forced symbol visibility? Is there a list of symbols that are included, no matter what? Is there a good reason for this behavior?
edit: Stranger still, if i remove <stdint.h> and change the uint32_t to int, this actually does compile.
If you go into the Report navigator and read the full error emitted by the clang tool, you'll see a big hint:
In module 'Darwin' imported from /Users/csrstka/Desktop/asdfasdf/asdfasdf/main.m:1:
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.13.sdk/usr/include/netinet/in.h:302:12: note: field has name 's_addr' here
in_addr_t s_addr;
As you can see, the existing in_addr is coming from the Darwin module, which is implicitly imported due to your #include of stdint.h, which is part of the Darwin module. You can see this if you go to Product > Perform Action > Preprocess in Xcode—instead of copying in all the headers you've imported, there's just one line about importing Darwin.C.stdint.
Basically, there are a few purposes for modules; they improve compile times by cutting down on redundant compilation tasks, and they prevent people from messing with library headers via #defines like you're trying to do. ;-) For more on Objective-C modules, how they work, and the rationale behind them, see this link:
https://clang.llvm.org/docs/Modules.html#introduction
Of particular interest to your question are the following excerpts:
The primary user-level feature of modules is the import operation, which provides access to the API of software libraries. However, today’s programs make extensive use of #include, and it is unrealistic to assume that all of this code will change overnight. Instead, modules automatically translate #include directives into the corresponding module import. For example, the include directive
#include <stdio.h>
will be automatically mapped to an import of the module std.io. Even with specific import syntax in the language, this particular feature is important for both adoption and backward compatibility: automatic translation of #include to import allows an application to get the benefits of modules (for all modules-enabled libraries) without any changes to the application itself. Thus, users can easily use modules with one compiler while falling back to the preprocessor-inclusion mechanism with other compilers.
And later on:
If any submodule of a module is imported into any part of a program, the entire top-level module is considered to be part of the program. As a consequence of this, Clang may diagnose conflicts between an entity declared in an unimported submodule and an entity declared in the current translation unit, and Clang may inline or devirtualize based on knowledge from unimported submodules.
Or, if you'd prefer to turn them off and get more traditional C-like behavior, you can simply set Enable Modules (C and Objective-C) to No in Xcode's Build Settings, or compile without the -fmodules flag if you're using the command line.

use of undeclared identifier 'git_diff_perfdata' with libgit2

I'm trying to write some code that uses git_diff_perfdata from the Libgit2 library.
git_diff_perfdata s;
However, when compiling on my Mac I get the error:
use of undeclared identifier 'git_diff_perfdata'
My understanding is that Libgit2 is meant to be used exclusively through the inclusion of git2.h. Is that correct?
git_diff_perfdata is defined in sys/diff.h and used in status.h
Should I be including sys/diff.h directly. If so, why? Alternatively, what errors might I be making? Looking at the header code I'm unable to see how sys/diff.h is included through anything that is included by git2.h.
Additionally, from what I can tell git_diff_perfdata isn't meant to be an opaque data type (i.e. only the pointer is defined).
I'm using the code downloaded from:
https://github.com/libgit2/libgit2/archive/v0.26.0.zip
The headers in sys are part of the public API, but they're a bit lower level. You can think of them as internal implementation details that have been made public because they might be useful to application developers. If you want to use them, include them directly.

C++/CLI exporting global symbols in assembly

I've got a situation where I can't change a CLI header that declares several symbols in the global scope, and then those symbols are then used by a function which IS inside a namespace, and that function is exported in an assembly I need to make use of.
Below is a bit of puedo code to help illustrate the Visual Studio setup. Also, I'm using the 2008 toolchain which is pre C++11 making the 'enum class' a managed object. Also note that it also doesn't have the access specifier (I did not write this) which makes it private.
ExportingAssembly.vcxproj
|->SomeHeader.h
| |->enum class SomeSymbol
|->SomeSource.c
|->SomeNamespace
|->void SomeFunction(SomeSymbol arg)
ImportingAssembly.vcxproj
|->Ref ExportingAssembly
|->ImportingSource.c
|->Using SomeNamespace;
|->void MyFu(){ SomeSumbol a = 0; SomeFunction(a); }
The problem is that those global symbols are obviously not visible to the importing assembly and if I include the header for those symbols it results in an incompatibility between my assembly and the one I'm importing
error C2664: 'ExportAssemblyNamespace::SomeFunction(SomeSymbol arg)': can't
convert parameter 1 from 'SomeSymbol" to 'SomeSymbol'
Now I CAN change the exported assembly (the project file and/or the source file) so I just hope I can somehow make those global symbols part of the exported assemblies' namespace so the importing assembly will see them. Or failing that, somehow locate the global symbols in the exported assembly (I can see the global symbols are in the PE MetaData Tables).
Any ideas. Or is a symbol without an access specifier private and impossible to make use of via referencing the assembly?
Or is a symbol without an access specifier private and impossible to make use of via referencing the assembly?
Yes, a symbol without an access specifier is private. It's not quite "impossible" to make use of; the only way is via reflection.
The fact that you have some things in a namespace, and some not, doesn't matter here. But you should have your function as part of a class, since global functions aren't part of the CLR. (C++/CLI creates a class to hold the global functions, but it's not a public class, and I think it has an invalid name anyway.)
Add the keyword public to your enum, and enclose your function in a public ref class.

C++/CLI error C1189 when I Include marshal library

I've got a application that is communicating with a PLC.
I have some libraries included for the communication but when I add marshal:
#include <msclr\marshal_cppstd.h>
it gives me the following error:
C1189: #error: The C++ Standard Library forbids macroizing keywords. Enable warning C4005 to find the forbidden macros.
C4005: 'inline': macro redefinition
this C4005 warning shows in
xkeycheck.h line 203 which contains:
#define inline EMIT WARNING C4005
and I get a ton more of errors(1800+).
So what does this error mean?
inline is a C++ keyword which this #define is re-defining. It's warning you that it's pretty risky to change the meaning of inline.
msclr\marshal_cppstd.h has functions marked with inline so this is probably the first occurrence of code using the re-defined inline definition and it's realizing that it is probably not what you're expecting.
I would question why xkeycheck.h is redefining inline -- perhaps inlining is not allowed with their library? Perhaps you need to push/pop the definition of inline around your include or #undef inline before your include?
Update: Did more research, I was assuming xkeycheck was from the PLC code. It's not. So, xkeycheck is set up to report this error if it sees that you've redefine any of the C++ keywords. inline in this case. As I said above, marshal_cppstd.h actually uses inline so that's the first sign of trouble and it's emitting the warning. So.... my advice is to search all your code and find out where you or a header you include has #define'd inline to something else.
I would put the cursor on inline and press F12 to go to the definition.