blob: 7056de0fa13ae5e39fd09ce87bfa22007cbf4d4d [file] [log] [blame]
// Copyright 2015 The Vanadium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package main
import (
"bytes"
"fmt"
"os"
"path"
"strings"
"text/template"
"v.io/jiri"
)
const singleHeaderTmpl = `/* Created by jiri-swift - DO NOT EDIT. */
/* Start of preamble from import "C" comments. */
{{.Includes}}
#import "go_types.h"
// These sizes (including C struct memory alignment/padding) isn't available from Go, so we make that available via CGo.
{{.Typedefs}}
/* End of preamble from import "C" comments. */
/* Start of boilerplate cgo prologue. */
{{.Prologue}}
/* End of boilerplate cgo prologue. */
#ifdef __cplusplus
extern "C"
#endif
{{.Exports}}
#ifdef __cplusplus
}
#endif
`
func runBuildCgo(jirix *jiri.X) error {
if flagBuildDirCgo == "" {
flagBuildDirCgo = sh.MakeTempDir()
}
sh.Pushd(flagBuildDirCgo)
for _, targetArch := range targetArchs {
compileCgo(jirix, targetArch)
installCgoBinary(jirix, targetArch)
}
copyCommonHeaders(jirix)
// Grab either the main arch we're building for or just the first -- we just need to make sure
// it's one that will have headers generated for it.
return generateSingleHeader(jirix, targetArchs[0])
}
func compileCgo(jirix *jiri.X, targetArch string) {
targetFlag := targetArch + "-ios"
verbose(jirix, "Building for target %v with build mode %v in dir %v\n", targetFlag, flagBuildMode, flagBuildDirCgo)
sh.Cmd("jiri", "go", "-target", targetFlag, "build", "-buildmode="+flagBuildMode, "-tags", "ios", "v.io/x/swift/main").Run()
sh.Cmd("jiri", "go", "-target", targetFlag, "install", "-buildmode="+flagBuildMode, "-tags", "ios", "v.io/x/swift/main").Run()
}
func installCgoBinary(jirix *jiri.X, targetArch string) {
// Install it to the Swift target directory
swiftTargetDir := getSwiftTargetDir(jirix)
sh.Cmd("mkdir", "-p", swiftTargetDir).Run()
var destLibPath string
switch flagBuildMode {
case buildModeArchive:
a := fmt.Sprintf("%v_%v.a", libraryBinaryName, targetArch)
destLibPath = path.Join(swiftTargetDir, a)
sh.Cmd("mv", "main.a", destLibPath).Run()
case buildModeShared:
dylib := fmt.Sprintf("%v_%v.dylib", libraryBinaryName, targetArch)
destLibPath = path.Join(swiftTargetDir, dylib)
sh.Cmd("mv", "main", dylib).Run()
sh.Cmd("install_name_tool", "-id", "@loader_path/"+dylib, dylib).Run()
sh.Cmd("mv", dylib, destLibPath).Run()
}
verbose(jirix, "Installed binary at %v\n", destLibPath)
verifyCgoBinaryArchOrPanic(destLibPath, targetArch)
}
func copyCommonHeaders(jirix *jiri.X) {
verbose(jirix, "Copying common shared headers between Swift and Go\n")
// Take types.h and make it into go_types.h
sh.Cmd("cp", path.Join(jirix.Root, "release/go/src/v.io/x/swift/types.h"), path.Join(getSwiftTargetDir(jirix), "go_types.h")).Run()
}
func generateSingleHeader(jirix *jiri.X, targetArch string) error {
verbose(jirix, "Generating header for Swift\n")
// Load and parse all the headers
generatedHeadersDir := fmt.Sprintf("%v/release/go/pkg/darwin_%v/v.io/x", jirix.Root, targetArch)
generatedHeadersPaths := findHeadersUnderPath(generatedHeadersDir)
hdrs := cgoHeaders{}
for _, file := range generatedHeadersPaths {
hdr, err := newCgoHeader(jirix, file)
if err != nil {
return err
}
hdrs = append(hdrs, hdr)
}
// Generate the header
data := struct {
Includes string
Typedefs string
Prologue string
Exports string
}{
Includes: strings.Join(hdrs.includes(), "\n"),
Typedefs: strings.Join(hdrs.typedefs(), "\n"),
Prologue: strings.Join(hdrs[0].prologue, "\n"), // Grab the first -- it is sufficient and complete.
Exports: strings.Join(hdrs.exports(), "\n"),
}
tmpl := template.Must(template.New("singleCgoHeader").Parse(singleHeaderTmpl))
var buf bytes.Buffer
if err := tmpl.Execute(&buf, data); err != nil {
return err
}
// Write it to disk
combinedHdrPath := path.Join(getSwiftTargetDir(jirix), "cgo_exports.h")
verbose(jirix, "Writing generated merged header to %v\n", combinedHdrPath)
// Remove the old file if it exists
if err := os.RemoveAll(combinedHdrPath); err != nil {
return err
}
f, err := os.Create(combinedHdrPath)
if err != nil {
return err
}
if _, err := buf.WriteTo(f); err != nil {
return err
}
return nil
}