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

Prevent extern "C" propagation #933

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

Jan200101
Copy link
Contributor

extern "C" is C++ specific and if we enable it our consumers are likely not C++.

`extern "C"` is C++ specific and if we enable it our consumers are likely not C++
@@ -137,14 +137,14 @@ if(LUAU_EXTERN_C)
# enable extern "C" for VM (lua.h, lualib.h) and Compiler (luacode.h) to make Luau friendlier to use from non-C++ languages
# note that we enable LUA_USE_LONGJMP=1 as well; otherwise functions like luaL_error will throw C++ exceptions, which can't be done from extern "C" functions
target_compile_definitions(Luau.VM PUBLIC LUA_USE_LONGJMP=1)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was unsure about if this should also be made private.

There doesn't appear to be anything in the header that makes use of it and a consumer may want to know about this.

target_compile_definitions(Luau.VM PUBLIC LUA_API=extern\"C\")
target_compile_definitions(Luau.Compiler PUBLIC LUACODE_API=extern\"C\")
target_compile_definitions(Luau.VM PRIVATE LUA_API=extern\"C\")
target_compile_definitions(Luau.Compiler PRIVATE LUACODE_API=extern\"C\")
endif()

if(LUAU_NATIVE)
target_compile_definitions(Luau.VM PUBLIC LUA_CUSTOM_EXECUTION=1)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as the other

@vegorov-rbx
Copy link
Collaborator

Sorry for the long response, we had to find someone who knows how CMake works.

This change will result in anything downstream from Luau.CodeGen that relies on LUACODEGEN_API having to also define it themselves, if they don't want to get linker errors.
If someone is linking against Luau.CodeGen from CMake and they're not C++, they do get the problem you are trying to solve, but this use case is rare - for a C library in CMake to link against a C++ library.

The better solution would have been to use a generator expression like $<$<COMPILE_LANGUAGE:CXX>:LUACODE_API=extern\"C\"), but that requires CMake 3.15+.
I believe we can do the same using an additional if statement to check for COMPILE_LANGUAGE.

@Jan200101
Copy link
Contributor Author

The better solution would have been to use a generator expression like $<$<COMPILE_LANGUAGE:CXX>:LUACODE_API=extern\"C\"), but that requires CMake 3.15+. I believe we can do the same using an additional if statement to check for COMPILE_LANGUAGE.

The generator expressions for the language appears to have been introduced with cmake 3.3 not 3.15, but that is still above the minimum version luau requires.

I don't think a single if would do the job, the if statement would be evaluated while luau is being configured, at which point CXX would be part of COMPILE_LANGUAGE.

I'm still looking around for other alternatives, but a massive workaround would be setting CMAKE_CXX_FLAGS

@TheGreatSageEqualToHeaven
Copy link
Contributor

TheGreatSageEqualToHeaven commented Jun 7, 2023

This change breaks exporting to a static and dynamic library which breaks embedding Luau in e.g CSharp. This is not a useful change and there should be specific settings added for exporting to a DLL, static library and basic extern "C" rather than one single setting

@Jan200101 @vegorov-rbx

@Jan200101
Copy link
Contributor Author

This change breaks exporting to a static and dynamic library which breaks embedding Luau in e.g CSharp.

As far as I can tell the cmake setup does not currently support building a dyanamic library, so this appears to a moot point, though it does affect how Luau would be consumed by C++ projects, breaking compatibility there.

This is not a useful change and there should be specific settings added for exporting to a DLL, static library and basic extern "C" rather than one single setting

This change needs to be done somehow regardless.

Most languages rely on the C ABI for their FFI and those that can consume the header files (e.g. C, Zig, etc.) may not understand extern "C".

An alternative (that I think would be best overall) would be dropping the build option and forcing extern C on the entire header when C++ is used.

@vegorov-rbx
Copy link
Collaborator

@zeux I wonder if we should always use "C" linkage without relying on CMake and place them in a block like:

#ifndef __cplusplus
extern "C" {
#endif

@zeux
Copy link
Collaborator

zeux commented Jun 20, 2023

Unfortunately we can't use extern "C" unconditionally when LUA_USE_LONGJMP is set to 0 -- this breaks exception handling because MSVC doesn't generate unwind tables, so calling functions like luaL_checknumber will abort instead of throwing a catchable exception.

It does seem like we'd need to have a separate LUA_EXTERN_C define :-/ I think the DLL export/import can still be handled as we do now (with CMake configuration without explicit support)?

@bjornbytes
Copy link
Contributor

I ran into this when trying to use Luau from a project written in C. When LUAU_EXTERN_C is enabled, C files can't include Luau headers, and when it's off C projects can't link to Luau libraries since they don't have C symbols.

In case it helps anyone, I have the following workaround which manually rips out the extern "C" compile definitions for projects linking to luau targets:

foreach(target Luau.VM Luau.Compiler)
  get_target_property(defs ${target} INTERFACE_COMPILE_DEFINITIONS)
  list(FILTER defs EXCLUDE REGEX [[LUA.*_API]])
  set_target_properties(${target} PROPERTIES INTERFACE_COMPILE_DEFINITIONS "${defs}")
endforeach()

# target_link_libraries(myproject Luau.VM Luau.Compiler Luau.Ast) etc.

This allows me to use luau as-is without having to apply this change on a fork.

@checkraisefold
Copy link
Contributor

I ran into this when trying to use Luau from a project written in C. When LUAU_EXTERN_C is enabled, C files can't include Luau headers, and when it's off C projects can't link to Luau libraries since they don't have C symbols.

In case it helps anyone, I have the following workaround which manually rips out the extern "C" compile definitions for projects linking to luau targets:

foreach(target Luau.VM Luau.Compiler)
  get_target_property(defs ${target} INTERFACE_COMPILE_DEFINITIONS)
  list(FILTER defs EXCLUDE REGEX [[LUA.*_API]])
  set_target_properties(${target} PROPERTIES INTERFACE_COMPILE_DEFINITIONS "${defs}")
endforeach()

# target_link_libraries(myproject Luau.VM Luau.Compiler Luau.Ast) etc.

This allows me to use luau as-is without having to apply this change on a fork.

This snippet fixed my issue just now when trying to do the exact same thing; Luau in a C project. Thanks!
Should be corrected; Luau can't be embedded in C projects easily at all with this caveat.

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

Successfully merging this pull request may close these issues.

6 participants