Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

importc fails to generate stub type #24604

Open
arnetheduck opened this issue Jan 6, 2025 · 12 comments · May be fixed by #24606
Open

importc fails to generate stub type #24604

arnetheduck opened this issue Jan 6, 2025 · 12 comments · May be fixed by #24606
Assignees

Comments

@arnetheduck
Copy link
Contributor

Description

type MyType {.importc, incompleteStruct.} = object

var v {.exportc.}: ptr MyType

My expectation, since there's no nodecl, would be a stub type generated (typedef struct MyType MyType; or similar.

Nim Version

devel, 2.0

Current Output

nim c testit.nim
/tmp/xxx/@mtest.nim.c:23:15: error: unknown type name ‘MyType’
   23 | N_LIB_PRIVATE MyType* v;
      |               ^~~~~~

Expected Output

No response

Known Workarounds

No response

Additional Information

No response

@litlighilit
Copy link
Contributor

but why importc instead of exportc

@arnetheduck
Copy link
Contributor Author

because the type is being imported from C (and defined in a C library)

@Araq
Copy link
Member

Araq commented Jan 8, 2025

Yet you want it to occur in the produced C file so as far as the compiler is concerned you export it...

@arnetheduck
Copy link
Contributor Author

arnetheduck commented Jan 8, 2025

Yet you want it to occur in the produced C file so as far as the compiler is concerned you export it...

well, that doesn't seem logical - that would place the responsibility of defining the type on nim, which is not the intent. The type is defined in a C library - what nim is supposed to to is create an opaque struct to be used for pointers but whose definition remains unknown to the compilation unit - nothing else. In fact, this is also what happens, exportc tries to define the type which is a worse outcome:

typedef struct MyType MyType;
struct MyType {
	char dummy;
};

@Araq
Copy link
Member

Araq commented Jan 8, 2025

Hmm ok, I get what you're saying.

@ringabout
Copy link
Member

It seems that lots of codebases relies on importc implying nodecl. e.g. status-im/nim-stint#166

@arnetheduck
Copy link
Contributor Author

hm, that's an unfortunate mess - the manual seems pretty clear on the intent of nodecl / header here, in favor of the interpretation of this issue, so technically such code is buggy (as buggy as the compiler :) ).

stint at least is easy to fix since nodecl works with all nim versions as documented.

@Araq
Copy link
Member

Araq commented Jan 9, 2025

Well the issue is subtle, "this type comes from C but also generate it in the C code" ... it's no wonder why we never encountered it before.

@arnetheduck
Copy link
Contributor Author

it's no wonder why we never encountered it before.

I think it's mostly because most of the time, people tend to use header which implies nodecl which is why it doesn't come up..

In this particular case, there's actually no header involved, or rather the nim file is the header because the relevant c code is also being generated and it doesn't need a header file. I could generate a c header file just to please nim, but that seems wrong too.

@Araq
Copy link
Member

Araq commented Jan 10, 2025

I think the solution here is:

type MyType {.incompleteStruct.} = object

var v {.exportc.}: ptr MyType

It is incomplete so the codegen should produce the "forward only" struct tag thing and it needs to emit the type as it is not imported.

Of course this doesn't work with today's compiler, but this can be done without breaking anybody's code (fingers crossed).

@arnetheduck
Copy link
Contributor Author

arnetheduck commented Jan 10, 2025

I think the solution here is:

This will still apply name mangling to the type - in theory it shouldn't matter since the name ultimately is arbitrary inside the compilation unit unless compilers do some fancy type-based aliasing analysis on this name in LTO mode, ie across CUs. I have no idea if this is a real issue or not, but it's something to consider at least - it would also maybe matter if you have something like:

type MyType {.incompleteStruct.} = object

proc f(v: ptr MyType) {.importc, header: "myheader.h".}

here, nodecl is implied by header so it might be that MyType must match by C name as well in the declaration of f.

@Araq
Copy link
Member

Araq commented Jan 11, 2025

To influence the name mangling .extern: "myname" can be used:

type MyType {.incompleteStruct, extern: "MyType".} = object

var v {.exportc.}: ptr MyType

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants