@@ -116,11 +116,29 @@ pub struct Opts {
116116 #[ cfg_attr( feature = "clap" , clap( long) ) ]
117117 pub pkg_name : Option < String > ,
118118
119+ /// When `--pkg-name` is specified, optionally specify a different package
120+ /// for exports.
121+ ///
122+ /// This allows you to put the exports and imports in separate packages when
123+ /// building a library. If only `--pkg-name` is specified, this will
124+ /// default to that value.
125+ #[ cfg_attr( feature = "clap" , clap( long, requires = "pkg_name" ) ) ]
126+ pub export_pkg_name : Option < String > ,
127+
119128 /// Print the version of the remote package being used for the shared WIT types.
120129 ///
121130 /// Must be specified in addition to the `pkg-name` flag.
122131 #[ cfg_attr( feature = "clap" , clap( long) ) ]
123132 pub print_remote_pkg_version : bool ,
133+
134+ /// When generating Go package names, include the WIT package version even
135+ /// if only one version of that package is referenced by the specified
136+ /// world.
137+ ///
138+ /// By default, the version will only be included in the name if the world
139+ /// references more than one version of the WIT package.
140+ #[ cfg_attr( feature = "clap" , clap( long) ) ]
141+ pub include_versions : bool ,
124142}
125143
126144impl Opts {
@@ -210,8 +228,12 @@ struct Go {
210228
211229impl Go {
212230 /// Adds the bindings module prefix to a package name.
213- fn mod_pkg ( & self , name : & str ) -> String {
214- let prefix = self . opts . pkg_name . as_deref ( ) . unwrap_or ( "wit_component" ) ;
231+ fn mod_pkg ( & self , for_export : bool , name : & str ) -> String {
232+ let prefix = for_export
233+ . then_some ( ( ) )
234+ . and ( self . opts . export_pkg_name . as_deref ( ) )
235+ . or ( self . opts . pkg_name . as_deref ( ) )
236+ . unwrap_or ( "wit_component" ) ;
215237 format ! ( r#""{prefix}/{name}""# )
216238 }
217239
@@ -229,14 +251,14 @@ impl Go {
229251 if local == owner && ( exported ^ in_import) {
230252 String :: new ( )
231253 } else {
232- let package = interface_name ( resolve, owner) ;
254+ let package = self . interface_name ( resolve, owner) ;
233255 let package = if exported {
234256 format ! ( "export_{package}" )
235257 } else {
236258 package
237259 } ;
238260 let prefix = format ! ( "{package}." ) ;
239- imports. insert ( self . mod_pkg ( & package) ) ;
261+ imports. insert ( self . mod_pkg ( exported , & package) ) ;
240262 prefix
241263 }
242264 }
@@ -610,7 +632,7 @@ func Lift{upper_kind}{camel}(handle int32) *witTypes.{upper_kind}Reader[{payload
610632 } else {
611633 format ! (
612634 "{}_" ,
613- interface_name(
635+ self . interface_name(
614636 resolve,
615637 Some (
616638 & self
@@ -722,7 +744,7 @@ impl WorldGenerator for Go {
722744 data. extend ( self . import ( resolve, func, Some ( name) ) ) ;
723745 }
724746 self . interfaces
725- . entry ( interface_name ( resolve, Some ( name) ) )
747+ . entry ( self . interface_name ( resolve, Some ( name) ) )
726748 . or_default ( )
727749 . extend ( data) ;
728750
@@ -741,7 +763,7 @@ impl WorldGenerator for Go {
741763 data. extend ( self . import ( resolve, func, None ) ) ;
742764 }
743765 self . interfaces
744- . entry ( interface_name ( resolve, None ) )
766+ . entry ( self . interface_name ( resolve, None ) )
745767 . or_default ( )
746768 . extend ( data) ;
747769 }
@@ -770,12 +792,13 @@ impl WorldGenerator for Go {
770792
771793 let data = generator. into ( ) ;
772794
795+ let name = self . interface_name ( resolve, Some ( name) ) ;
773796 if exported {
774797 & mut self . export_interfaces
775798 } else {
776799 & mut self . interfaces
777800 }
778- . entry ( interface_name ( resolve , Some ( name) ) )
801+ . entry ( name)
779802 . or_default ( )
780803 . extend ( data) ;
781804 }
@@ -818,7 +841,7 @@ impl WorldGenerator for Go {
818841 }
819842 let data = generator. into ( ) ;
820843 self . interfaces
821- . entry ( interface_name ( resolve, None ) )
844+ . entry ( self . interface_name ( resolve, None ) )
822845 . or_default ( )
823846 . extend ( data) ;
824847 }
@@ -883,16 +906,14 @@ impl WorldGenerator for Go {
883906 files. push (
884907 "go.mod" ,
885908 format ! (
886- r#"module {}
909+ r#"module wit_component
887910
888911go 1.25
889912
890913require (
891- go.bytecodealliance.org/pkg {}
914+ go.bytecodealliance.org/pkg {REMOTE_PKG_VERSION }
892915)
893916"# ,
894- self . opts. pkg_name. as_deref( ) . unwrap_or( "wit_component" ) ,
895- REMOTE_PKG_VERSION ,
896917 )
897918 . as_bytes ( ) ,
898919 ) ;
@@ -1215,7 +1236,7 @@ func {camel}({go_params}) {go_results} {{
12151236 let sig = resolve. wasm_signature ( variant, func) ;
12161237 let core_module_name = interface. map ( |v| resolve. name_world_key ( v) ) ;
12171238 let export_name = func. legacy_core_export_name ( core_module_name. as_deref ( ) ) ;
1218- let name = func_name ( resolve, interface, func) ;
1239+ let name = self . func_name ( resolve, interface, func) ;
12191240
12201241 let params = sig
12211242 . params
@@ -1340,7 +1361,7 @@ func wasm_export_post_return_{name}(result {results}) {{
13401361 let results = self . func_results ( resolve, func, interface, false , & mut imports) ;
13411362
13421363 self . export_interfaces
1343- . entry ( interface_name ( resolve, interface) )
1364+ . entry ( self . interface_name ( resolve, interface) )
13441365 . or_default ( )
13451366 . extend ( InterfaceData {
13461367 code : format ! (
@@ -1459,12 +1480,13 @@ func wasm_export_{name}({params}) {results} {{
14591480 & func. name ,
14601481 ) ;
14611482
1483+ let name = self . interface_name ( resolve, interface) ;
14621484 if in_import || !exported {
14631485 & mut self . interfaces
14641486 } else {
14651487 & mut self . export_interfaces
14661488 }
1467- . entry ( interface_name ( resolve , interface ) )
1489+ . entry ( name )
14681490 . or_default ( )
14691491 . extend ( data) ;
14701492 }
@@ -1483,6 +1505,47 @@ func wasm_export_{name}({params}) {results} {{
14831505 }
14841506 } )
14851507 }
1508+
1509+ fn interface_name ( & self , resolve : & Resolve , interface : Option < & WorldKey > ) -> String {
1510+ match interface {
1511+ Some ( WorldKey :: Name ( name) ) => name. to_snake_case ( ) ,
1512+ Some ( WorldKey :: Interface ( id) ) => {
1513+ let interface = & resolve. interfaces [ * id] ;
1514+ let package = & resolve. packages [ interface. package . unwrap ( ) ] ;
1515+ let package_has_multiple_versions = resolve. packages . iter ( ) . any ( |( _, p) | {
1516+ p. name . namespace == package. name . namespace
1517+ && p. name . name == package. name . name
1518+ && p. name . version != package. name . version
1519+ } ) ;
1520+ let version = if package_has_multiple_versions || self . opts . include_versions {
1521+ if let Some ( version) = & package. name . version {
1522+ format ! ( "{}_" , version. to_string( ) . replace( [ '.' , '-' , '+' ] , "_" ) )
1523+ } else {
1524+ String :: new ( )
1525+ }
1526+ } else {
1527+ String :: new ( )
1528+ } ;
1529+ let namespace = package. name . namespace . to_snake_case ( ) ;
1530+ let package = package. name . name . to_snake_case ( ) ;
1531+ let interface = interface. name . as_ref ( ) . unwrap ( ) . to_snake_case ( ) ;
1532+ format ! ( "{namespace}_{package}_{version}{interface}" )
1533+ }
1534+ None => "wit_world" . into ( ) ,
1535+ }
1536+ }
1537+
1538+ fn func_name (
1539+ & self ,
1540+ resolve : & Resolve ,
1541+ interface : Option < & WorldKey > ,
1542+ func : & Function ,
1543+ ) -> String {
1544+ let prefix = self . interface_name ( resolve, interface) ;
1545+ let name = func. name . to_snake_case ( ) . replace ( '.' , "_" ) ;
1546+
1547+ format ! ( "{prefix}_{name}" )
1548+ }
14861549}
14871550
14881551struct FunctionGenerator < ' a > {
@@ -1772,13 +1835,16 @@ for index := 0; index < int({length}); index++ {{
17721835 }
17731836
17741837 let name = func. item_name ( ) . to_upper_camel_case ( ) ;
1775- let package = format ! ( "export_{}" , interface_name( resolve, self . interface) ) ;
1838+ let package = format ! (
1839+ "export_{}" ,
1840+ self . generator. interface_name( resolve, self . interface)
1841+ ) ;
17761842
17771843 let call = match & func. kind {
17781844 FunctionKind :: Freestanding | FunctionKind :: AsyncFreestanding => {
17791845 let args = operands. join ( ", " ) ;
17801846 let call = format ! ( "{package}.{name}({args})" ) ;
1781- self . imports . insert ( self . generator . mod_pkg ( & package) ) ;
1847+ self . imports . insert ( self . generator . mod_pkg ( true , & package) ) ;
17821848 call
17831849 }
17841850 FunctionKind :: Constructor ( ty) => {
@@ -1789,7 +1855,7 @@ for index := 0; index < int({length}); index++ {{
17891855 . unwrap ( )
17901856 . to_upper_camel_case ( ) ;
17911857 let call = format ! ( "{package}.Make{ty}({args})" ) ;
1792- self . imports . insert ( self . generator . mod_pkg ( & package) ) ;
1858+ self . imports . insert ( self . generator . mod_pkg ( true , & package) ) ;
17931859 call
17941860 }
17951861 FunctionKind :: Method ( _) | FunctionKind :: AsyncMethod ( _) => {
@@ -2934,42 +3000,6 @@ const (
29343000 }
29353001}
29363002
2937- fn interface_name ( resolve : & Resolve , interface : Option < & WorldKey > ) -> String {
2938- match interface {
2939- Some ( WorldKey :: Name ( name) ) => name. to_snake_case ( ) ,
2940- Some ( WorldKey :: Interface ( id) ) => {
2941- let interface = & resolve. interfaces [ * id] ;
2942- let package = & resolve. packages [ interface. package . unwrap ( ) ] ;
2943- let package_has_multiple_versions = resolve. packages . iter ( ) . any ( |( _, p) | {
2944- p. name . namespace == package. name . namespace
2945- && p. name . name == package. name . name
2946- && p. name . version != package. name . version
2947- } ) ;
2948- let version = if package_has_multiple_versions {
2949- if let Some ( version) = & package. name . version {
2950- format ! ( "{}_" , version. to_string( ) . replace( [ '.' , '-' , '+' ] , "_" ) )
2951- } else {
2952- String :: new ( )
2953- }
2954- } else {
2955- String :: new ( )
2956- } ;
2957- let namespace = package. name . namespace . to_snake_case ( ) ;
2958- let package = package. name . name . to_snake_case ( ) ;
2959- let interface = interface. name . as_ref ( ) . unwrap ( ) . to_snake_case ( ) ;
2960- format ! ( "{namespace}_{package}_{version}{interface}" )
2961- }
2962- None => "wit_world" . into ( ) ,
2963- }
2964- }
2965-
2966- fn func_name ( resolve : & Resolve , interface : Option < & WorldKey > , func : & Function ) -> String {
2967- let prefix = interface_name ( resolve, interface) ;
2968- let name = func. name . to_snake_case ( ) . replace ( '.' , "_" ) ;
2969-
2970- format ! ( "{prefix}_{name}" )
2971- }
2972-
29733003fn wasm_type ( ty : WasmType ) -> & ' static str {
29743004 match ty {
29753005 WasmType :: I32 => "int32" ,
0 commit comments