# Formalizing @cdecl

**URL:** <https://forums.swift.org/t/formalizing-cdecl/40677>\
**Category:** Pitches\
**Created:** [September 27, 2020, 12:15am UTC](https://forums.swift.org/t/formalizing-cdecl/40677 "2020-09-27T00:15:13Z")\
**Posts on this page:** 1\
**Showing post:** 31

<div class="post-metadata">

**Author:** ![jrose](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/jrose/32/408_2.png) [@jrose](https://forums.swift.org/u/jrose)\
**Post date:** [October 5, 2020, 6:41am UTC](https://forums.swift.org/t/formalizing-cdecl/40677/31 "2020-10-05T06:41:45Z")

</div>

> [@jayton](#):
>
> It seems to me that `@_cdecl` actually does two distinct things:
> 
> - Constrain the types and calling conventions of a function such that it can be called from C (or other languages with C interop). This overlaps with `@convention(c)` , but I don’t really know how closely.
> - Define the linkage name of a function, which is used for static and dynamic linking and also shows up in backtraces. This overlaps with `@_silgen_name` .

`@_silgen_name` is the elephant in the room. Part of that is right there in the name of the attribute: "SILGen name". `@_silgen_name` doesn't just change the symbol name of a function; it changes how the compiler _itself_ sees the function, well before it's emitted.\* It also does not change the calling convention, but the Swift calling convention is _mostly_ compatible with C's on _most_ platforms and those "mosts" should freak you out.

The other thing `@_silgen_name` does is let you declare functions that exist without importing a module or header file. That's inherently unsafe, but it's also [how Rust calls C functions](https://doc.rust-lang.org/book/ch19-01-unsafe-rust.html#using-extern-functions-to-call-external-code)\*\*, so I don't want to say it's forever off the table. For now, though, it'd be a big shift in how what Swift allows, so I want to set this aside. I _really_ want to set this aside.

> [@Geordie\_J](#):
>
> I’m not sure of its current status but we have had to use `@_silgen_name` instead of `@_cdecl` in the past due to the latter's lack of availability on Linux.

I don't think this was ever a thing; please go see if you can remove `@_silgen_name`!

\* For what it's worth, I believe `@_cdecl` is currently implemented the same way, and I'm not sure we should keep that. I'd rather preserve the Swift name until we get down to LLVM, which is where we've resolved all names and no longer need to look in imported modules.

\*\* Though often these `extern` blocks are generated by a tool like [`bindgen`](https://rust-lang.github.io/rust-bindgen/) rather than written by hand, precisely because it's easy to get it wrong.

* * *

Okay, so what about the other aspect: the separation of name control from calling convention? The main thing I'm thinking about here is the goal: call a Swift-defined function from C.

> [@jayton](#):
>
> Language orthogonality aside, it’s not entirely obvious that exporting an API to C should default to changing the linkage name. Instead of generating C prototypes for exported Swift functions, an exporter could generate stubs like this:

Jens's stub here is clever, and mostly works because we've kept our mangling scheme based on the C identifier character set. I had originally dismissed the idea because I didn't think of a way to do it without language extensions. I would still like a way to control the symbol name too, but maybe that really is separable.

Anyway, the conclusion I'm coming to is that we should have an attribute like `@available` where there's one required parameter—the language—and then several keyword arguments. That leaves room for expansion in the future.

```swift
@extern(c)
@extern(c, name: fookit_setup)
@extern(c++, abi: itanium)

```

If we follow the convention of `@objc`, then `@extern(c)` would generate a C function but use the Swift symbol name, and `@extern(c, name: fookit_setup)` would actually change the symbol name. That's fairly subtle, though, so maybe we'd want to do something else? (As has been pointed out above, you can always write a wrapper function that has the right C name if you also care about the name in Swift.)

Does the name really need a parameter label, since it's the most common thing? It does if we want to support Objective-C selectors without quotes, and I think quotes are bad here because the compiler _does_ need to validate it a little. Okay, technically you can distinguish them because selectors with arguments always end in a colon, but still.

I'm not the first in the thread to come up with the argument-based attribute, of course; I'm just throwing my weight behind it. Y'all have convinced me. :-)

One thing that's missing here is the [`@objc @cdecl` thing](https://forums.swift.org/t/formalizing-cdecl/40677/5). How do you distinguish between a C function that allows ObjC types from a C function that doesn't? Maybe something like `@extern(c, allow: objc)`? That _does_ scale to `@extern(c, allow: c++)`, which is a thing that happens sometimes… But if anyone has better suggestions, I'm all ears.

\*\*\* You can't do this with Objective-C methods because you need to be able to implement a protocol method in both Objective-C and Swift and have it work from the other language. And it wouldn't work at all with classes.

* * *

Finally, the name. I don't _love_ the name `extern` because I feel like it's more strongly associated with it's "declare but not define" meaning than its "share with other files/libraries/languages" meaning, but it does have massive precedent. My thoughts on the other suggestions in the thread:

- `@linkage` isn't a term most people would know, I think. (It means more than just C vs. C++ in C-land, too.)

- `@decl` feels very generic (though I appreciate that Swift is just another choice there)

- [`@export` _really_ sounds like it's related to imports to me](https://forums.swift.org/t/exported-and-fixing-import-visibility/9415/).

- `@callableBy` feels wordy and doesn't work on things other than functions.

- `@convention(c)` doesn't feel like it'll scale to all our uses, and `@extern @convention(c)` seems needlessly verbose even if `@extern` also supports a symbol name.

* * *

I was hoping I'd come to conclusions at the end of these update posts, but there aren't too many to be had. I'm glad we're having the discussion, though!

P.S. I don't like anyone's names for the alternate `-emit-objc-header` either. Bleah!

---

_[View the full topic](https://forums.swift.org/t/formalizing-cdecl/40677)._
