Skip to content

Commit

Permalink
feat: build of shared/static libraries
Browse files Browse the repository at this point in the history
* add the correct extension according to the lib type and target os
* archive the generated header file
  • Loading branch information
borgoat committed Oct 31, 2022
1 parent c71d8ec commit b267970
Show file tree
Hide file tree
Showing 6 changed files with 97 additions and 0 deletions.
4 changes: 4 additions & 0 deletions internal/artifact/artifact.go
Expand Up @@ -66,6 +66,8 @@ const (
ScoopManifest
// SBOM is a Software Bill of Materials file.
SBOM
// Header is a C header file, generated for CGo library builds.
Header
)

func (t Type) String() string {
Expand Down Expand Up @@ -104,6 +106,8 @@ func (t Type) String() string {
return "PKGBUILD"
case SrcInfo:
return "SRCINFO"
case Header:
return "Header"
default:
return "unknown"
}
Expand Down
31 changes: 31 additions & 0 deletions internal/builders/golang/build.go
Expand Up @@ -192,6 +192,8 @@ func (*Builder) Build(ctx *context.Context, build config.Build, options api.Opti
}
}

addHeaderArtifactIfLibrary(ctx, build, options)

ctx.Artifacts.Add(artifact)
return nil
}
Expand Down Expand Up @@ -366,3 +368,32 @@ func hasMain(file *ast.File) bool {
}
return false
}

func addHeaderArtifactIfLibrary(ctx *context.Context, build config.Build, options api.Options) {
for _, s := range build.BuildDetails.Flags {
if s == "-buildmode=c-shared" || s == "-buildmode=c-archive" {
fullPathWithoutExt := strings.TrimSuffix(options.Path, options.Ext)
basePath := filepath.Base(fullPathWithoutExt)
fullPath := fullPathWithoutExt + ".h"
headerName := basePath + ".h"

header := &artifact.Artifact{
Type: artifact.Header,
Path: fullPath,
Name: headerName,
Goos: options.Goos,
Goarch: options.Goarch,
Goamd64: options.Goamd64,
Goarm: options.Goarm,
Gomips: options.Gomips,
Extra: map[string]interface{}{
artifact.ExtraBinary: headerName,
artifact.ExtraExt: ".h",
artifact.ExtraID: build.ID,
},
}

ctx.Artifacts.Add(header)
}
}
}
1 change: 1 addition & 0 deletions internal/pipe/archive/archive.go
Expand Up @@ -91,6 +91,7 @@ func (Pipe) Run(ctx *context.Context) error {
filter := []artifact.Filter{artifact.Or(
artifact.ByType(artifact.Binary),
artifact.ByType(artifact.UniversalBinary),
artifact.ByType(artifact.Header),
)}
if len(archive.Builds) > 0 {
filter = append(filter, artifact.ByIDs(archive.Builds...))
Expand Down
20 changes: 20 additions & 0 deletions internal/pipe/build/build.go
Expand Up @@ -212,6 +212,26 @@ func buildOptionsForTarget(ctx *context.Context, build config.Build, target stri
}

func extFor(target string, flags config.FlagArray) string {
if strings.Contains(target, "darwin") {
for _, s := range flags {
if s == "-buildmode=c-shared" {
return ".dylib"
}
if s == "-buildmode=c-archive" {
return ".a"
}
}
}
if strings.Contains(target, "linux") {
for _, s := range flags {
if s == "-buildmode=c-shared" {
return ".so"
}
if s == "-buildmode=c-archive" {
return ".a"
}
}
}
if strings.Contains(target, "windows") {
for _, s := range flags {
if s == "-buildmode=c-shared" {
Expand Down
20 changes: 20 additions & 0 deletions internal/pipe/build/build_test.go
Expand Up @@ -426,6 +426,26 @@ func TestSkipBuild(t *testing.T) {
require.Len(t, ctx.Artifacts.List(), 0)
}

func TestExtDarwin(t *testing.T) {
require.Equal(t, "", extFor("darwin_amd64", config.FlagArray{}))
require.Equal(t, "", extFor("darwin_arm64", config.FlagArray{}))
require.Equal(t, "", extFor("darwin_amd64", config.FlagArray{"-tags=dev", "-v"}))
require.Equal(t, ".dylib", extFor("darwin_amd64", config.FlagArray{"-tags=dev", "-v", "-buildmode=c-shared"}))
require.Equal(t, ".dylib", extFor("darwin_arm64", config.FlagArray{"-buildmode=c-shared"}))
require.Equal(t, ".a", extFor("darwin_amd64", config.FlagArray{"-buildmode=c-archive"}))
require.Equal(t, ".a", extFor("darwin_arm64", config.FlagArray{"-tags=dev", "-v", "-buildmode=c-archive"}))
}

func TestExtLinux(t *testing.T) {
require.Equal(t, "", extFor("linux_amd64", config.FlagArray{}))
require.Equal(t, "", extFor("linux_386", config.FlagArray{}))
require.Equal(t, "", extFor("linux_amd64", config.FlagArray{"-tags=dev", "-v"}))
require.Equal(t, ".so", extFor("linux_amd64", config.FlagArray{"-tags=dev", "-v", "-buildmode=c-shared"}))
require.Equal(t, ".so", extFor("linux_386", config.FlagArray{"-buildmode=c-shared"}))
require.Equal(t, ".a", extFor("linux_amd64", config.FlagArray{"-buildmode=c-archive"}))
require.Equal(t, ".a", extFor("linux_386", config.FlagArray{"-tags=dev", "-v", "-buildmode=c-archive"}))
}

func TestExtWindows(t *testing.T) {
require.Equal(t, ".exe", extFor("windows_amd64", config.FlagArray{}))
require.Equal(t, ".exe", extFor("windows_386", config.FlagArray{}))
Expand Down
21 changes: 21 additions & 0 deletions www/docs/customization/build.md
Expand Up @@ -517,3 +517,24 @@ will evaluate to the list of first class ports as defined in the Go wiki.

You can read more about it
[here](https://github.com/golang/go/wiki/PortingPolicy#first-class-ports).

## Building shared or static libraries

GoReleaser supports compiling and releasing libraries, by configuring the [Go build mode](https://pkg.go.dev/cmd/go#hdr-Build_modes).

This can be set with `buildmode` in your build `flags`. It currently supports `c-shared` and `c-archive`.

GoReleaser will:

* set the correct file extension for the target OS.
* package the generated header file (`.h`) in the release bundle.

```yaml
# .goreleaser.yaml
builds:
-
id: "my-library"

# Configure the buildmode flag to output a shared library
flags: -buildmode=c-shared # or "c-archive" for a static library
```

0 comments on commit b267970

Please sign in to comment.