Use Go modules with delocate.

This makes running go test, etc., in util/fipstools/delocate work! This
adds a go_executable command to CMake like:

  go_executable(delocate boringssl.googlesource.com/boringssl/util/fipstools/delocate)

which internally gets dependencies and whatnot so it behaves like usual
Go.

Update-Note: delocate has been rearranged a bit.
Change-Id: I244a7317dd8d4f2ab77a0daa624ed3e0b385faef
Reviewed-on: https://boringssl-review.googlesource.com/31885
Commit-Queue: David Benjamin <davidben@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
Reviewed-by: Adam Langley <agl@google.com>
This commit is contained in:
David Benjamin 2018-09-13 16:37:28 -05:00 committed by CQ bot account: commit-bot@chromium.org
parent 302ef5ee12
commit 5baee45652
31 changed files with 262 additions and 25 deletions

View File

@ -334,6 +334,43 @@ if(OPENSSL_SMALL)
add_definitions(-DOPENSSL_SMALL)
endif()
function(go_executable dest package)
set(godeps "${CMAKE_SOURCE_DIR}/util/godeps.go")
if(${CMAKE_VERSION} VERSION_LESS "3.7" OR
NOT ${CMAKE_GENERATOR} STREQUAL "Ninja")
# The DEPFILE parameter to add_custom_command is new as of CMake 3.7 and
# only works with Ninja. Query the sources at configure time. Additionally,
# everything depends on go.mod. That affects what external packages to use.
execute_process(COMMAND ${GO_EXECUTABLE} run ${godeps} -format cmake
-pkg ${package}
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
OUTPUT_VARIABLE sources
RESULT_VARIABLE godeps_result)
add_custom_command(OUTPUT ${dest}
COMMAND ${GO_EXECUTABLE} build
-o ${CMAKE_CURRENT_BINARY_DIR}/${dest} ${package}
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
DEPENDS ${sources} ${CMAKE_SOURCE_DIR}/go.mod)
else()
# Ninja expects the target in the depfile to match the output. This is a
# relative path from the build directory.
string(LENGTH "${CMAKE_BINARY_DIR}" root_dir_length)
math(EXPR root_dir_length "${root_dir_length} + 1")
string(SUBSTRING "${CMAKE_CURRENT_BINARY_DIR}" ${root_dir_length} -1 target)
set(target "${target}/${dest}")
set(depfile "${CMAKE_CURRENT_BINARY_DIR}/${dest}.d")
add_custom_command(OUTPUT ${dest}
COMMAND ${GO_EXECUTABLE} build
-o ${CMAKE_CURRENT_BINARY_DIR}/${dest} ${package}
COMMAND ${GO_EXECUTABLE} run ${godeps} -format depfile
-target ${target} -pkg ${package} -out ${depfile}
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
DEPENDS ${godeps} ${CMAKE_SOURCE_DIR}/go.mod
DEPFILE ${depfile})
endif()
endfunction()
# CMake's iOS support uses Apple's multiple-architecture toolchain. It takes an
# architecture list from CMAKE_OSX_ARCHITECTURES, leaves CMAKE_SYSTEM_PROCESSOR
# alone, and expects all architecture-specific logic to be conditioned within

View File

@ -141,21 +141,12 @@ if(FIPS_DELOCATE)
set_target_properties(bcm_c_generated_asm PROPERTIES COMPILE_OPTIONS "-S")
set_target_properties(bcm_c_generated_asm PROPERTIES POSITION_INDEPENDENT_CODE ON)
function(prepend_path values prefix output)
set(result)
foreach(value ${values})
list(APPEND result "${prefix}/${value}")
endforeach(value)
set(${output} ${result} PARENT_SCOPE)
endfunction()
prepend_path("${BCM_ASM_SOURCES}" "${CMAKE_CURRENT_BINARY_DIR}" DELOCATE_ASM_ARGS)
go_executable(delocate boringssl.googlesource.com/boringssl/util/fipstools/delocate)
add_custom_command(
OUTPUT bcm-delocated.S
COMMAND ${GO_EXECUTABLE} run util/fipstools/delocate.go util/fipstools/delocate.peg.go util/fipstools/ar.go util/fipstools/const.go -a $<TARGET_FILE:bcm_c_generated_asm> -o ${CMAKE_CURRENT_BINARY_DIR}/bcm-delocated.S ${DELOCATE_ASM_ARGS}
DEPENDS bcm_c_generated_asm ${BCM_ASM_SOURCES} ${CMAKE_SOURCE_DIR}/util/fipstools/delocate.go ${CMAKE_SOURCE_DIR}/util/fipstools/delocate.peg.go ${CMAKE_SOURCE_DIR}/util/fipstools/ar.go ${CMAKE_SOURCE_DIR}/util/fipstools/const.go
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
COMMAND ./delocate -a $<TARGET_FILE:bcm_c_generated_asm> -o bcm-delocated.S ${BCM_ASM_SOURCES}
DEPENDS bcm_c_generated_asm delocate ${BCM_ASM_SOURCES}
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
)
add_library(
@ -171,11 +162,13 @@ if(FIPS_DELOCATE)
set_target_properties(bcm_hashunset PROPERTIES POSITION_INDEPENDENT_CODE ON)
set_target_properties(bcm_hashunset PROPERTIES LINKER_LANGUAGE C)
go_executable(inject-hash
boringssl.googlesource.com/boringssl/util/fipstools/inject-hash)
add_custom_command(
OUTPUT bcm.o
COMMAND ${GO_EXECUTABLE} run util/fipstools/inject-hash.go util/fipstools/ar.go util/fipstools/const.go -o ${CMAKE_CURRENT_BINARY_DIR}/bcm.o -in-archive $<TARGET_FILE:bcm_hashunset>
DEPENDS bcm_hashunset ${CMAKE_SOURCE_DIR}/util/fipstools/inject-hash.go ${CMAKE_SOURCE_DIR}/util/fipstools/ar.go ${CMAKE_SOURCE_DIR}/util/fipstools/const.go
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
COMMAND ./inject-hash -o bcm.o -in-archive $<TARGET_FILE:bcm_hashunset>
DEPENDS bcm_hashunset inject-hash
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
)
# The outputs of add_custom_command cannot be referenced outside of the

View File

@ -25,6 +25,8 @@ import (
"sort"
"strconv"
"strings"
"boringssl.googlesource.com/boringssl/util/fipstools/fipscommon"
)
// inputFile represents a textual assembly file.
@ -1405,7 +1407,7 @@ func transform(w stringWriter, inputs []inputFile) error {
w.WriteString(".type BORINGSSL_bcm_text_hash, @object\n")
w.WriteString(".size BORINGSSL_bcm_text_hash, 64\n")
w.WriteString("BORINGSSL_bcm_text_hash:\n")
for _, b := range uninitHashValue {
for _, b := range fipscommon.UninitHashValue {
w.WriteString(".byte 0x" + strconv.FormatUint(uint64(b), 16) + "\n")
}
@ -1423,7 +1425,7 @@ func parseInputs(inputs []inputFile) error {
}
defer arFile.Close()
ar, err := ParseAR(arFile)
ar, err := fipscommon.ParseAR(arFile)
if err != nil {
return err
}

View File

@ -14,7 +14,7 @@
// ar.go contains functions for parsing .a archive files.
package main
package fipscommon
import (
"bytes"

View File

@ -12,11 +12,11 @@
// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
package main
package fipscommon
// uninitHashValue is the default hash value that we inject into the module.
// UninitHashValue is the default hash value that we inject into the module.
// This value need only be distinct, i.e. so that we can safely
// search-and-replace it in an object file.
var uninitHashValue = [64]byte{
var UninitHashValue = [64]byte{
0xae, 0x2c, 0xea, 0x2a, 0xbd, 0xa6, 0xf3, 0xec, 0x97, 0x7f, 0x9b, 0xf6, 0x94, 0x9a, 0xfc, 0x83, 0x68, 0x27, 0xcb, 0xa0, 0xa0, 0x9f, 0x6b, 0x6f, 0xde, 0x52, 0xcd, 0xe2, 0xcd, 0xff, 0x31, 0x80, 0xa2, 0xd4, 0xc3, 0x66, 0x0f, 0xc2, 0x6a, 0x7b, 0xf4, 0xbe, 0x39, 0xa2, 0xd7, 0x25, 0xdb, 0x21, 0x98, 0xe9, 0xd5, 0x53, 0xbf, 0x5c, 0x32, 0x06, 0x83, 0x34, 0x0c, 0x65, 0x89, 0x52, 0xbd, 0x1f,
}

View File

@ -28,6 +28,8 @@ import (
"io"
"io/ioutil"
"os"
"boringssl.googlesource.com/boringssl/util/fipstools/fipscommon"
)
func do(outPath, oInput string, arInput string) error {
@ -43,7 +45,7 @@ func do(outPath, oInput string, arInput string) error {
}
defer arFile.Close()
ar, err := ParseAR(arFile)
ar, err := fipscommon.ParseAR(arFile)
if err != nil {
return err
}
@ -145,12 +147,12 @@ func do(outPath, oInput string, arInput string) error {
// Replace the default hash value in the object with the calculated
// value and write it out.
offset := bytes.Index(objectBytes, uninitHashValue[:])
offset := bytes.Index(objectBytes, fipscommon.UninitHashValue[:])
if offset < 0 {
return errors.New("did not find uninitialised hash value in object file")
}
if bytes.Index(objectBytes[offset+1:], uninitHashValue[:]) >= 0 {
if bytes.Index(objectBytes[offset+1:], fipscommon.UninitHashValue[:]) >= 0 {
return errors.New("found two occurrences of uninitialised hash value in object file")
}

203
util/godeps.go Normal file
View File

@ -0,0 +1,203 @@
// Copyright (c) 2018, Google Inc.
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
// godeps prints out dependencies of a package in either CMake or Make depfile
// format, for incremental rebuilds.
//
// The depfile format is preferred. It works correctly when new files are added.
// However, CMake only supports depfiles for custom commands with Ninja and
// starting CMake 3.7. For other configurations, we also support CMake's format,
// but CMake must be rerun when file lists change.
package main
import (
"flag"
"fmt"
"go/build"
"os"
"path/filepath"
"sort"
"strings"
)
var (
format = flag.String("format", "cmake", "The format to output to, either 'cmake' or 'depfile'")
mainPkg = flag.String("pkg", "", "The package to print dependencies for")
target = flag.String("target", "", "The name of the output file")
out = flag.String("out", "", "The path to write the output to. If unset, this is stdout")
)
func cMakeQuote(in string) string {
// See https://cmake.org/cmake/help/v3.0/manual/cmake-language.7.html#quoted-argument
var b strings.Builder
b.Grow(len(in))
// Iterate over in as bytes.
for i := 0; i < len(in); i++ {
switch c := in[i]; c {
case '\\', '"':
b.WriteByte('\\')
b.WriteByte(c)
case '\t':
b.WriteString("\\t")
case '\r':
b.WriteString("\\r")
case '\n':
b.WriteString("\\n")
default:
b.WriteByte(in[i])
}
}
return b.String()
}
func writeCMake(outFile *os.File, files []string) error {
for i, file := range files {
if i != 0 {
if _, err := outFile.WriteString(";"); err != nil {
return err
}
}
if _, err := outFile.WriteString(cMakeQuote(file)); err != nil {
return err
}
}
return nil
}
func makeQuote(in string) string {
// See https://www.gnu.org/software/make/manual/make.html#Rule-Syntax
var b strings.Builder
b.Grow(len(in))
// Iterate over in as bytes.
for i := 0; i < len(in); i++ {
switch c := in[i]; c {
case '$':
b.WriteString("$$")
case '#', '\\', ' ':
b.WriteByte('\\')
b.WriteByte(c)
default:
b.WriteByte(c)
}
}
return b.String()
}
func writeDepfile(outFile *os.File, files []string) error {
if _, err := fmt.Fprintf(outFile, "%s:", makeQuote(*target)); err != nil {
return err
}
for _, file := range files {
if _, err := fmt.Fprintf(outFile, " %s", makeQuote(file)); err != nil {
return err
}
}
_, err := outFile.WriteString("\n")
return err
}
func appendPrefixed(list, newFiles []string, prefix string) []string {
for _, file := range newFiles {
list = append(list, filepath.Join(prefix, file))
}
return list
}
func main() {
flag.Parse()
if len(*mainPkg) == 0 {
fmt.Fprintf(os.Stderr, "-pkg argument is required.\n")
os.Exit(1)
}
var isDepfile bool
switch *format {
case "depfile":
isDepfile = true
case "cmake":
isDepfile = false
default:
fmt.Fprintf(os.Stderr, "Unknown format: %q\n", *format)
os.Exit(1)
}
if isDepfile && len(*target) == 0 {
fmt.Fprintf(os.Stderr, "-target argument is required for depfile.\n")
os.Exit(1)
}
done := make(map[string]struct{})
var files []string
var recurse func(pkgName string) error
recurse = func(pkgName string) error {
pkg, err := build.Default.Import(pkgName, ".", 0)
if err != nil {
return err
}
// Skip standard packages.
if pkg.Goroot {
return nil
}
// Skip already-visited packages.
if _, ok := done[pkg.Dir]; ok {
return nil
}
done[pkg.Dir] = struct{}{}
files = appendPrefixed(files, pkg.GoFiles, pkg.Dir)
files = appendPrefixed(files, pkg.CgoFiles, pkg.Dir)
// Include ignored Go files. A subsequent change may cause them
// to no longer be ignored.
files = appendPrefixed(files, pkg.IgnoredGoFiles, pkg.Dir)
// Recurse into imports.
for _, importName := range pkg.Imports {
if err := recurse(importName); err != nil {
return err
}
}
return nil
}
if err := recurse(*mainPkg); err != nil {
fmt.Fprintf(os.Stderr, "Error getting dependencies: %s\n", err)
os.Exit(1)
}
sort.Strings(files)
outFile := os.Stdout
if len(*out) != 0 {
var err error
outFile, err = os.Create(*out)
if err != nil {
fmt.Fprintf(os.Stderr, "Error writing output: %s\n", err)
os.Exit(1)
}
defer outFile.Close()
}
var err error
if isDepfile {
err = writeDepfile(outFile, files)
} else {
err = writeCMake(outFile, files)
}
if err != nil {
fmt.Fprintf(os.Stderr, "Error writing output: %s\n", err)
os.Exit(1)
}
}