Skip to content

Commit

Permalink
chore: address issues getting vapor_example working (#92)
Browse files Browse the repository at this point in the history
- Separate headers between public and private.
- Combine headers found by inspection with those in the modulemap.
- Add support for custom defines for Swift and clang.

Related to #50.
  • Loading branch information
cgrindel committed Dec 24, 2022
1 parent f54a7f1 commit 44b0830
Show file tree
Hide file tree
Showing 10 changed files with 366 additions and 53 deletions.
2 changes: 2 additions & 0 deletions gazelle/internal/spdump/manifest_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ func TestNewManifestFromJSON(t *testing.T) {
},
},
},
Settings: []spdump.TargetSetting{},
},
{
Name: "MySwiftPackageTests",
Expand All @@ -64,6 +65,7 @@ func TestNewManifestFromJSON(t *testing.T) {
ByName: &spdump.ByNameReference{Name: "MySwiftPackage"},
},
},
Settings: []spdump.TargetSetting{},
},
},
}
Expand Down
73 changes: 72 additions & 1 deletion gazelle/internal/spdump/target.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
package spdump

import "encoding/json"
import (
"encoding/json"
"errors"
"fmt"

"github.com/cgrindel/swift_bazel/gazelle/internal/jsonutils"
)

type TargetType int

Expand Down Expand Up @@ -37,6 +43,7 @@ type Target struct {
Name string
Type TargetType
Dependencies []TargetDependency
Settings []TargetSetting
}

func (t *Target) Imports() []string {
Expand All @@ -59,3 +66,67 @@ func (ts Targets) FindByName(name string) *Target {
}
return nil
}

// TargetSetting

type ToolType int

const (
UnknownToolType ToolType = iota
ClangToolType
)

type TargetSettingKind int

const (
UnknownTargetSettingKind = iota
DefineTargetSettingKind
)

type TargetSetting struct {
Tool ToolType
Kind TargetSettingKind
Defines []string
}

func (ts *TargetSetting) UnmarshalJSON(b []byte) error {
var anyMap map[string]any
err := json.Unmarshal(b, &anyMap)
if err != nil {
return err
}

toolStr, err := jsonutils.StringAtKey(anyMap, "tool")
if err != nil {
return err
}
switch toolStr {
case "c":
ts.Tool = ClangToolType
default:
ts.Tool = UnknownToolType
}

kindMap, err := jsonutils.MapAtKey(anyMap, "kind")
if err != nil {
return err
}
var mke *jsonutils.MissingKeyError
if defineMap, err := jsonutils.MapAtKey(kindMap, "define"); err != nil {
if err != nil && !errors.As(err, &mke) {
return err
}
} else {
ts.Kind = DefineTargetSettingKind
for _, anyVal := range defineMap {
switch define := anyVal.(type) {
case string:
ts.Defines = append(ts.Defines, define)
default:
return fmt.Errorf("unexpected type %T for define value", define)
}
}
}

return nil
}
29 changes: 29 additions & 0 deletions gazelle/internal/spdump/target_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package spdump_test

import (
"encoding/json"
"testing"

"github.com/cgrindel/swift_bazel/gazelle/internal/spdump"
Expand Down Expand Up @@ -41,3 +42,31 @@ func TestTargetsByName(t *testing.T) {
actual = targets.FindByName("DoesNotExist")
assert.Nil(t, actual)
}

func TestTargetSettingUnmarshalJSON(t *testing.T) {
expected := []spdump.TargetSetting{
{
Tool: spdump.ClangToolType,
Kind: spdump.DefineTargetSettingKind,
Defines: []string{"__APPLE_USE_RFC_3542"},
},
}

var settings []spdump.TargetSetting
err := json.Unmarshal([]byte(targetSettingsJSON), &settings)
assert.NoError(t, err)
assert.Equal(t, expected, settings)
}

const targetSettingsJSON = `
[
{
"kind" : {
"define" : {
"_0" : "__APPLE_USE_RFC_3542"
}
},
"tool" : "c"
}
]
`
26 changes: 26 additions & 0 deletions gazelle/internal/swiftpkg/target.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ type Target struct {
Path string
Sources []string
Dependencies []*TargetDependency
CSettings *ClangSettings
}

func NewTargetFromManifestInfo(descT *spdesc.Target, dumpT *spdump.Target) (*Target, error) {
Expand Down Expand Up @@ -83,6 +84,11 @@ func NewTargetFromManifestInfo(descT *spdesc.Target, dumpT *spdump.Target) (*Tar
}
}

cSettings, err := NewClangSettingsFromManifestInfo(dumpT.Settings)
if err != nil {
return nil, err
}

return &Target{
Name: descT.Name,
C99name: descT.C99name,
Expand All @@ -91,6 +97,7 @@ func NewTargetFromManifestInfo(descT *spdesc.Target, dumpT *spdump.Target) (*Tar
Path: descT.Path,
Sources: descT.Sources,
Dependencies: tdeps,
CSettings: cSettings,
}, nil
}

Expand All @@ -101,3 +108,22 @@ func (t *Target) Imports() []string {
}
return imports
}

// ClangSettings

type ClangSettings struct {
Defines []string
}

func NewClangSettingsFromManifestInfo(dumpTS []spdump.TargetSetting) (*ClangSettings, error) {
cSettings := &ClangSettings{}
for _, ts := range dumpTS {
if ts.Tool != spdump.ClangToolType {
continue
}
if ts.Kind == spdump.DefineTargetSettingKind {
cSettings.Defines = append(cSettings.Defines, ts.Defines...)
}
}
return cSettings, nil
}
59 changes: 32 additions & 27 deletions swiftpkg/internal/clang_files.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

load("@bazel_skylib//lib:paths.bzl", "paths")
load("@bazel_skylib//lib:sets.bzl", "sets")
load("@cgrindel_bazel_starlib//bzllib:defs.bzl", "lists")
load("//swiftpkg/internal/modulemap_parser:declarations.bzl", dts = "declaration_types")
load("//swiftpkg/internal/modulemap_parser:parser.bzl", modulemap_parser = "parser")
load(":repository_files.bzl", "repository_files")
Expand Down Expand Up @@ -84,10 +85,7 @@ def _get_hdr_paths_from_modulemap(repository_ctx, modulemap_path):
return hdrs

def _remove_prefix(path, prefix):
if prefix == None or path == None:
return path
prefix_len = len(prefix)
return path[prefix_len:] if path.startswith(prefix) else path
return _remove_prefixes([path], prefix)[0]

def _remove_prefixes(paths_list, prefix):
if prefix == None:
Expand Down Expand Up @@ -119,7 +117,7 @@ def _collect_files(
hdrs_set = sets.make()
srcs_set = sets.make()
others_set = sets.make()
includes_set = sets.make()
public_includes_set = sets.make()
modulemap = None
modulemap_orig_path = None
for orig_path in paths_list:
Expand All @@ -128,10 +126,11 @@ def _collect_files(
if ext == ".h":
if _is_include_hdr(orig_path, public_includes = public_includes):
sets.insert(hdrs_set, path)
sets.insert(includes_set, paths.dirname(path))
sets.insert(public_includes_set, paths.dirname(path))
else:
sets.insert(srcs_set, path)
elif ext == ".c":
elif lists.contains([".c", ".S", ".so", ".o"], ext):
# Acceptable sources: https://bazel.build/reference/be/c-cpp#cc_library.srcs
sets.insert(srcs_set, path)
elif ext == ".modulemap" and _is_public_modulemap(path):
if modulemap != None:
Expand All @@ -148,40 +147,46 @@ def _collect_files(
others = sets.to_list(others_set)

# Add each directory that contains a private header to the includes
private_hdr_dirs = sets.make([
private_includes_set = sets.make([
paths.dirname(src)
for src in srcs
if _is_hdr(src)
])
includes_set = sets.union(includes_set, private_hdr_dirs)

# Be sure to add any parent directories to the includes list
# Some clang files reference their header files from different relative paths
for include in sets.to_list(includes_set):
parts = include.split("/")
for idx, _part in enumerate(parts):
path = "/".join(parts[0:idx])
if path != "":
sets.insert(includes_set, path)

includes = sets.to_list(includes_set)

# If we found a public modulemap, get the headers from there. This
# overrides any hdrs that we found by inspection.
# # Be sure to add any parent directories to the includes list
# # Some clang files reference their header files from different relative paths
# for include in sets.to_list(public_includes_set):
# parts = include.split("/")
# for idx, _part in enumerate(parts):
# path = "/".join(parts[0:idx])
# if path != "":
# sets.insert(public_includes_set, path)

public_includes = sets.to_list(public_includes_set)
private_includes = sets.to_list(private_includes_set)

# The apple/swift-crypto package has a CCryptoBoringSSL target that has a
# modulemap in their include directory, but it only lists the top-level
# header. The modulemap spec suggests that the header is parsed and all of
# the referenced headers are included. For now, we will just add the
# modulempa hdrs to the ones that we have already found.
if modulemap_orig_path != None:
hdrs = _get_hdr_paths_from_modulemap(
mm_hdrs = _get_hdr_paths_from_modulemap(
repository_ctx,
modulemap_orig_path,
)
hdrs = _remove_prefixes(hdrs, remove_prefix)
else:
hdrs = sets.to_list(hdrs_set)
mm_hdrs = _remove_prefixes(mm_hdrs, remove_prefix)
mm_hdrs_set = sets.make(mm_hdrs)
hdrs_set = sets.union(hdrs_set, mm_hdrs_set)

hdrs = sets.to_list(hdrs_set)

# Remove the prefixes before returning the results
return struct(
hdrs = sorted(hdrs),
srcs = sorted(srcs),
includes = sorted(includes),
public_includes = sorted(public_includes),
private_includes = sorted(private_includes),
modulemap = modulemap,
others = sorted(others),
)
Expand Down
Loading

0 comments on commit 44b0830

Please sign in to comment.