blob: 477c03c900d06b166588133f11c7c7272b5e9d81 [file] [log] [blame]
// Copyright (C) 2016 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package cc
import (
"flag"
"fmt"
"os"
"path/filepath"
"strings"
"android.googlesource.com/platform/tools/gpu/framework/device"
"android.googlesource.com/platform/tools/gpu/framework/file"
"android.googlesource.com/platform/tools/gpu/framework/log"
"android.googlesource.com/platform/tools/gpu/tools/maker/config"
"android.googlesource.com/platform/tools/gpu/tools/maker/cpp"
"android.googlesource.com/platform/tools/gpu/tools/maker/cpp/gcc"
"android.googlesource.com/platform/tools/gpu/tools/maker/cpp/msvc"
"android.googlesource.com/platform/tools/gpu/tools/maker/cpp/ndk"
"android.googlesource.com/platform/tools/gpu/tools/maker/graph"
)
var (
logfile = flag.String("logfile", "", "Writes logging to a file instead of stdout")
debug = flag.Bool("d", false, "Generate debug binaries")
)
func getLogger() log.Context {
handler := log.Std(log.Normal)
if len(*logfile) > 0 {
os.MkdirAll(filepath.Dir(*logfile), 0755)
file, err := os.Create(*logfile)
if err != nil {
panic(err)
}
handler = log.Writer(log.Normal, file)
}
handler, _ = log.Channel(handler)
return log.Background().PreFilter(log.Limit(log.NoticeLevel)).Filter(log.Pass).Handler(handler)
}
type Target struct {
Name string
SourceFiles []string
Gtest cpp.Config
Gmock cpp.Config
Gapic cpp.Config
GapicTests cpp.Config
Gapii cpp.Config
Gapir cpp.Config
GapirTests cpp.Config
Spy cpp.Config
Replayd cpp.Config
}
func (t Target) Extend(n Target) Target {
return Target{
SourceFiles: append(append([]string{}, t.SourceFiles...), n.SourceFiles...),
Gtest: t.Gtest.Extend(n.Gtest),
Gmock: t.Gmock.Extend(n.Gmock),
Gapic: t.Gapic.Extend(n.Gapic),
GapicTests: t.GapicTests.Extend(n.GapicTests),
Gapii: t.Gapii.Extend(n.Gapii),
Gapir: t.Gapir.Extend(n.Gapir),
GapirTests: t.GapirTests.Extend(n.GapirTests),
Spy: t.Spy.Extend(n.Spy),
Replayd: t.Replayd.Extend(n.Replayd),
}
}
func (t Target) Build(ctx log.Context) {
ctx = ctx.Enter(t.Name)
// Build gtest into a library
gtestSource := config.Paths.GtestRoot.Join("src").Glob("gtest-all.cc", "gtest_main.cc").AsSet()
gtestLib := cpp.MakeStaticLibrary(ctx, gtestSource, t.Gtest, true)
// Build gmock into a library
gmockSource := config.Paths.GmockRoot.Join("src").Glob("gmock-all.cc").AsSet()
gmockLib := cpp.MakeStaticLibrary(ctx, gmockSource, t.Gmock, true)
// Gather the source files for gapic
gapicSource := config.Paths.GapicRoot.Glob(t.SourceFiles...).
Append(config.Paths.GapicRoot.Join("gl").Glob(t.SourceFiles...)...).
Append(config.Paths.GapicRoot.Join(strings.ToLower(t.Gapic.Target.ABI.OS.String())).Glob(t.SourceFiles...)...).
NotMatching("*_test.cpp").AsSet().Union(t.Gapic.AdditionalSources)
// Build the gapic static library.
gapicLib := cpp.MakeStaticLibrary(ctx, gapicSource, t.Gapic, true)
// Gather the source files for gapii
gapiiSource := config.Paths.GapiiRoot.Glob(t.SourceFiles...).
Append(config.Paths.GapiiRoot.Join(strings.ToLower(t.Gapii.Target.ABI.OS.String())).Glob(t.SourceFiles...)...).
NotMatching("*_test.cpp").
NotMatching("link_interceptor.cpp"). // only need in the .so
// Generated by APIC
Append(config.Paths.GapiiRoot.Join("gles_imports.cpp")).
Append(config.Paths.GapiiRoot.Join("gles_exports.cpp")).
AsSet().Union(gapicSource)
for i := 0; i < 7; i++ {
gapiiSource.Append(config.Paths.GapiiRoot.Join(fmt.Sprintf("gles_spy_%d.cpp", i)))
}
for i := 0; i < 2; i++ {
gapiiSource.Append(config.Paths.GapiiRoot.Join(fmt.Sprintf("gles_spy_subroutines_%d.cpp", i)))
}
// Gather the source files for gapir
gapirSource := config.Paths.GapirRoot.Glob(t.SourceFiles...).
Append(config.Paths.GapirRoot.Join(strings.ToLower(t.Gapir.Target.ABI.OS.String())).Glob(t.SourceFiles...)...).
NotMatching("*_test.cpp").
// Generated by APIC
Append(config.Paths.GapirRoot.Join("gfx_api.cpp")).AsSet()
// Build the gapir static library.
gapirLib := cpp.MakeStaticLibrary(ctx, gapirSource, t.Gapir, true)
// Build the spy (libgapii.so) from the gapii source files.
// TODO Investigate linker flags to use to check for undefined symbols
gapiiSo := cpp.MakeDynamicLibrary(ctx, "spy", gapiiSource, t.Spy)
if t.Replayd.Target.ABI.OS == device.OSKind_ANDROID {
// Copy: bin/android-<abi>/<debug/release>/libgapii.so -> bin/android-<abi>/libgapii.so
cpp.MakeCopy(ctx, gapiiSo, t.Spy.OutputDir.Join("..", gapiiSo.Basename()), t.Spy)
}
// Build gapir from the gapir static library and Main.cpp.
replaydSource := file.Paths(config.Paths.ReplaydRoot.Join("main.cpp")).AsSet()
replaydInputs := replaydSource.Append(gapirLib, gapicLib)
replayd := cpp.MakeExecutable(ctx, "gapir", replaydInputs, t.Replayd)
// Build tests.
gapicTestSource := config.Paths.GapicRoot.Glob(t.SourceFiles...).
Append(config.Paths.GapicRoot.Join(strings.ToLower(t.Gapic.Target.ABI.OS.String())).Glob(t.SourceFiles...)...).
Matching("*_test.cpp").AsSet()
gapicTestInputs := gapicTestSource.Append(gtestLib, gmockLib, gapicLib)
gapicTest := cpp.MakeExecutable(ctx, "gapic-tests", gapicTestInputs, t.GapicTests)
gapirTestSource := config.Paths.GapirRoot.Glob(t.SourceFiles...).
Append(config.Paths.GapirRoot.Join(strings.ToLower(t.Gapir.Target.ABI.OS.String())).Glob(t.SourceFiles...)...).
Matching("*_test.cpp").AsSet()
gapirTestInputs := gapirTestSource.Append(gtestLib, gmockLib, gapirLib, gapicLib)
gapirTest := cpp.MakeExecutable(ctx, "gapir-tests", gapirTestInputs, t.GapirTests)
if t.Replayd.Target.ABI.OS == config.HostOS {
cpp.MakeRunTest(ctx, gapicTest, t.GapicTests)
cpp.MakeRunTest(ctx, gapirTest, t.GapirTests)
src, dst := replayd, config.Paths.BinRoot.Join(replayd.Basename())
cpp.MakeCopy(ctx, src, dst, t.Replayd)
}
if config.HostOS == device.OSKind_LINUX {
deqpTest := config.Paths.GPURoot.Join("tools/deqp.sh")
cpp.MakeRunTest(ctx, deqpTest, t.Gapii)
graph.List(ctx, graph.Virtual("cc:deqp.sh:run")).DependsOn(gapiiSo)
}
}
func base(toolchain *cpp.Toolchain, target *config.Target) Target {
defs := map[string]string{
"TARGET_OS_" + strings.ToUpper(target.ABI.OS.String()): "1",
}
base := cpp.Config{
Toolchain: toolchain,
Target: target,
Defines: defs,
}
if *debug {
base.Flavor = "debug"
base.OptimizationLevel = cpp.NoOptimization
base.Defines["LOG_LEVEL"] = "3" // LOG_LEVEL_DEBUG
} else {
base.Flavor = "release"
base.OptimizationLevel = cpp.FullOptimization
}
if toolchain == gcc.GCC {
base.LibrarySearchPaths = file.Paths(file.Abs("/usr/local/lib")).AsSet()
}
if toolchain != msvc.MSVC {
base.Libraries = []string{"stdc++"}
base.CompilerArgs = []string{"-std=c++11"}
} else {
base.Flavor += "-msvc"
}
base.OutputDir = config.Paths.BinRoot.Join(strings.ToLower(target.ABI.OS.String()+"-"+target.ABI.Architecture.String()), base.Flavor)
return Target{
Name: target.ABI.Name,
SourceFiles: []string{"*.cpp", "*.cc"},
Gtest: base.Extend(cpp.Config{
Name: "gtest",
IncludeSearchPaths: file.Paths(
config.Paths.GtestRoot,
config.Paths.GtestRoot.Join("include"),
).AsSet(),
}),
Gmock: base.Extend(cpp.Config{
Name: "gmock",
IncludeSearchPaths: file.Paths(
config.Paths.GmockRoot,
config.Paths.GmockRoot.Join("include"),
config.Paths.GtestRoot,
config.Paths.GtestRoot.Join("include"),
).AsSet(),
}),
Gapic: base.Extend(cpp.Config{
Name: "gapic",
AdditionalSources: file.Paths(
config.Paths.GapicRoot.Join("coder").Glob("*.cpp")...).AsSet(),
IncludeSearchPaths: file.Paths(config.Paths.CCRoot).AsSet(),
}),
GapicTests: base.Extend(cpp.Config{
Name: "gapic-tests",
IncludeSearchPaths: file.Paths(
config.Paths.CCRoot,
config.Paths.GmockRoot.Join("include"),
config.Paths.GtestRoot.Join("include"),
).AsSet(),
}),
Gapii: base.Extend(cpp.Config{
Name: "gapii",
IncludeSearchPaths: file.Paths(config.Paths.CCRoot).AsSet(),
}),
Gapir: base.Extend(cpp.Config{
Name: "gapir",
IncludeSearchPaths: file.Paths(config.Paths.CCRoot).AsSet(),
}),
GapirTests: base.Extend(cpp.Config{
Name: "gapir-tests",
IncludeSearchPaths: file.Paths(
config.Paths.CCRoot,
config.Paths.GmockRoot.Join("include"),
config.Paths.GtestRoot.Join("include"),
).AsSet(),
}),
Spy: base.Extend(cpp.Config{
Name: "gapii",
IncludeSearchPaths: file.Paths(config.Paths.CCRoot).AsSet(),
}),
Replayd: base.Extend(cpp.Config{
Name: "gapir",
IncludeSearchPaths: file.Paths(config.Paths.CCRoot).AsSet(),
}),
}
}
// Generate "maker" graph for building the cpp code.
func Graph() {
// Note this logger is captured in the build graph. There is no good place
// to call logger.Close()
ctx := getLogger()
noext := ""
switch config.TargetOS {
case device.OSKind_LINUX:
base(gcc.GCC, config.GetTarget(config.TargetOS, device.Architecture_X86_64)).Extend(Target{
GapicTests: cpp.Config{
Libraries: []string{"pthread"},
},
GapirTests: cpp.Config{
Libraries: []string{"dl", "GL", "m", "pthread", "X11", "rt"},
},
Replayd: cpp.Config{
Libraries: []string{"dl", "GL", "m", "pthread", "X11", "rt"},
},
Spy: cpp.Config{
Name: "libgapii",
Libraries: []string{"pthread"},
},
}).Build(ctx)
case device.OSKind_OSX:
osx := base(gcc.GCC, config.GetTarget(config.TargetOS, device.Architecture_X86_64)).Extend(Target{
SourceFiles: []string{"*.mm"},
Gapii: cpp.Config{
AdditionalSources: file.Paths(
config.Paths.GapiiRoot.Join("osx", "opengl_framework_exports.cpp")).AsSet(),
},
Spy: cpp.Config{
Name: "OpenGL",
OutputExt: &noext,
},
GapirTests: cpp.Config{
LinkerArgs: []string{
"-framework", "Cocoa",
"-framework", "OpenGL",
},
Libraries: []string{"pthread"},
},
Replayd: cpp.Config{
LinkerArgs: []string{
"-framework", "Cocoa",
"-framework", "OpenGL",
},
Libraries: []string{"pthread"},
},
})
osx.Spy.OutputDir = osx.Spy.OutputDir.Join("OpenGL.framework", "Versions", "A")
osx.Build(ctx)
case device.OSKind_WINDOWS:
base(gcc.GCC, config.GetTarget(config.TargetOS, device.Architecture_X86_64)).Extend(Target{
Gapii: cpp.Config{
AdditionalSources: file.Paths(
config.Paths.GapiiRoot.Join("windows", "opengl32_resolve.cpp")).AsSet(),
},
Spy: cpp.Config{
Libraries: []string{"ws2_32", "opengl32", "gdi32", "user32"},
},
GapirTests: cpp.Config{
Libraries: []string{"ws2_32", "opengl32", "gdi32", "user32"},
},
Replayd: cpp.Config{
Libraries: []string{"ws2_32", "opengl32", "gdi32", "user32"},
},
}).Build(ctx)
if config.HostOS == device.OSKind_WINDOWS {
base(msvc.MSVC, config.GetTarget(config.HostOS, device.Architecture_X86_64)).Extend(Target{
Gapii: cpp.Config{
AdditionalSources: file.Paths(
config.Paths.GapiiRoot.Join("windows", "opengl32_resolve.cpp")).AsSet(),
},
Spy: cpp.Config{
Name: "opengl32",
AdditionalSources: file.Paths(config.Paths.GapiiRoot.Join("windows", "opengl32_x64.asm")).AsSet(),
ModuleDefinition: config.Paths.GapiiRoot.Join("windows", "opengl32_exports.def"),
Libraries: []string{"ws2_32", "opengl32", "gdi32", "user32"},
},
GapirTests: cpp.Config{
Libraries: []string{"ws2_32", "opengl32", "gdi32", "user32"},
},
Replayd: cpp.Config{
Libraries: []string{"ws2_32", "opengl32", "gdi32", "user32"},
},
}).Build(ctx)
}
}
// A bit of the Android crazy linker from the NDK. This is used to
// relink the program to use spy interceptors on non-rooted devices.
crazy := config.Paths.CCRoot.Join("third_party", "ndk", "crazy_linker", "src")
crazy_source := file.Paths(
crazy.Join("crazy_linker_elf_view.cpp"),
crazy.Join("crazy_linker_error.cpp"),
crazy.Join("linker_phdr.cpp"),
).AsSet()
app_glue := config.Paths.CCRoot.Join("third_party", "ndk", "native_app_glue")
android_target := Target{
GapicTests: cpp.Config{
Toolchain: ndk.EXE,
Libraries: []string{"log", "android", "z", "m"},
},
GapirTests: cpp.Config{
Toolchain: ndk.EXE,
Libraries: []string{"EGL", "log", "android", "z", "m"},
},
Replayd: cpp.Config{
Libraries: []string{"EGL", "log", "android", "z", "m"},
IncludeSearchPaths: file.Paths(app_glue.Join()).AsSet(),
AdditionalSources: file.Paths(app_glue.Join("android_native_app_glue.c")).AsSet(),
},
Spy: cpp.Config{
Libraries: []string{"log", "z", "m", "dl"},
IncludeSearchPaths: file.Paths(crazy).AsSet(),
AdditionalSources: crazy_source.Append(
config.Paths.GapiiRoot.Join("android", "link_interceptor.cpp")),
},
}
base(ndk.APK, config.GetTarget(device.OSKind_ANDROID, device.Architecture_ARMv7a)).Extend(android_target).Build(ctx)
base(ndk.APK, config.GetTarget(device.OSKind_ANDROID, device.Architecture_ARMv8a)).Extend(android_target).Build(ctx)
// uncomment the following line for building Android x86 targets for emulator, if you configured x86 compiler
//base(ndk.APK, config.GetTarget(device.OSKind_ANDROID, device.Architecture_X86)).Extend(android_target).Build(ctx)
}