Adds GN build files for building in GN based projects.

Review URL: https://codereview.chromium.org//690923003

git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@41673 260f80e4-7a28-3924-810f-c04153c831b5
This commit is contained in:
zra@google.com 2014-11-11 22:03:55 +00:00
parent 21fa0f35f8
commit b4d3762221
8 changed files with 738 additions and 0 deletions

28
BUILD.gn Normal file
View file

@ -0,0 +1,28 @@
# Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
# for details. All rights reserved. Use of this source code is governed by a
# BSD-style license that can be found in the LICENSE file.
config("dart_config") {
defines = []
if (is_debug) {
defines += ["DEBUG"]
} else {
defines += ["NDEBUG"]
}
cflags = [
"-Werror",
"-Wall",
"-Wextra", # Also known as -W.
"-Wno-unused-parameter",
"-Wnon-virtual-dtor",
"-Wvla",
"-Wno-conversion-null",
"-Woverloaded-virtual",
"-g3",
"-ggdb3",
"-fno-rtti",
"-fno-exceptions",
]
}

69
runtime/BUILD.gn Normal file
View file

@ -0,0 +1,69 @@
# Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
# for details. All rights reserved. Use of this source code is governed by a
# BSD-style license that can be found in the LICENSE file.
static_library("libdart") {
configs += ["..:dart_config"]
deps = [
"vm:libdart_lib",
"vm:libdart_vm",
"third_party/jscre:libjscre",
"third_party/double-conversion/src:libdouble_conversion",
":generate_version_cc_file",
]
include_dirs = [
".",
]
sources = [
"include/dart_api.h",
"include/dart_debugger_api.h",
"include/dart_mirrors_api.h",
"include/dart_native_api.h",
"vm/dart_api_impl.cc",
"vm/debugger_api_impl.cc",
"vm/mirrors_api_impl.cc",
"vm/native_api_impl.cc",
"vm/version.h",
"$target_gen_dir/version.cc",
]
defines = [
# Using DART_SHARED_LIB to export the Dart API entries.
"DART_SHARED_LIB",
]
}
action("generate_version_cc_file") {
deps = [
":libdart_dependency_helper",
]
inputs = [
"../tools/utils.py",
"../tools/print_version.py",
"../tools/VERSION",
"vm/version_in.cc",
]
output = "$target_gen_dir/version.cc"
outputs = [ output, ]
script = "../tools/make_version.py"
args = [
"--output", rebase_path(output, root_build_dir),
"--input", rebase_path("vm/version_in.cc", root_build_dir),
]
}
executable("libdart_dependency_helper") {
deps = [
"vm:libdart_lib_withcore",
"vm:libdart_lib",
"vm:libdart_vm",
"vm:libdart_platform",
"third_party/jscre:libjscre",
"third_party/double-conversion/src:libdouble_conversion",
]
sources = [
"vm/libdart_dependency_helper.cc",
]
}

175
runtime/bin/BUILD.gn Normal file
View file

@ -0,0 +1,175 @@
# Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
# for details. All rights reserved. Use of this source code is governed by a
# BSD-style license that can be found in the LICENSE file.
declare_args() {
dart_io_support = false
}
template("gen_library_src_path") {
assert(defined(invoker.sources), "Need sources in $target_name")
assert(defined(invoker.output), "Need output in $target_name")
action(target_name) {
visibility = [ ":*" ] # Only targets in this file can see this.
script = "../tools/gen_library_src_paths.py"
inputs = [
"../tools/gen_library_src_paths.py",
"builtin_in.cc",
]
outputs = [ invoker.output, ]
name = invoker.name
kind = invoker.kind
args = [
"--output", rebase_path(invoker.output, root_build_dir),
"--input_cc", rebase_path("builtin_in.cc", root_build_dir),
"--include", "bin/builtin.h",
"--var_name", "dart::bin::Builtin::${name}_${kind}_paths_",
"--library_name", "dart:${name}",] +
rebase_path(invoker.sources, root_build_dir)
}
}
builtin_sources_gypi =
exec_script("../../tools/gypi_to_gn.py",
[rebase_path("builtin_sources.gypi")],
"scope",
["builtin_sources.gypi"])
gen_library_src_path("generate_builtin_cc_file") {
name = "_builtin"
kind = "source"
sources = builtin_sources_gypi.sources
output = "$target_gen_dir/builtin_gen.cc"
}
iolib_sources_gypi =
exec_script("../../tools/gypi_to_gn.py",
[rebase_path("../../sdk/lib/io/iolib_sources.gypi")],
"scope",
["../../sdk/lib/io/iolib_sources.gypi"])
iolib_sources = rebase_path(iolib_sources_gypi.sources, ".", "../../sdk/lib/io")
gen_library_src_path("generate_io_cc_file") {
name = "io"
kind = "source"
sources = ["../../sdk/lib/io/io.dart"] + iolib_sources
output = "$target_gen_dir/io_gen.cc"
}
io_sources_gypi =
exec_script("../../tools/gypi_to_gn.py",
[rebase_path("io_sources.gypi")],
"scope",
["io_sources.gypi"])
gen_library_src_path("generate_io_patch_cc_file") {
name = "io"
kind = "patch"
sources = io_sources_gypi.sources
output = "$target_gen_dir/io_patch_gen.cc"
}
config("libdart_builtin_config") {
libs = [
"dl",
]
}
builtin_impl_sources_gypi =
exec_script("../../tools/gypi_to_gn.py",
[rebase_path("builtin_impl_sources.gypi")],
"scope",
["builtin_impl_sources.gypi"])
static_library("libdart_builtin") {
configs += ["../..:dart_config"]
public_configs = [":libdart_builtin_config"]
deps = [
":generate_builtin_cc_file",
":generate_io_cc_file",
":generate_io_patch_cc_file",
]
include_dirs = [
"..",
]
set_sources_assignment_filter(["*_test.cc", "*_test.h"])
sources = [
"log_android.cc",
"log_linux.cc",
"log_macos.cc",
"log_win.cc",
] + builtin_impl_sources_gypi.sources
}
static_library("libdart_withcore") {
configs += ["../..:dart_config"]
deps = [
"../vm:libdart_lib_withcore",
"../vm:libdart_vm",
"../vm:libdart_platform",
"../third_party/jscre:libjscre",
"../third_party/double-conversion/src:libdouble_conversion",
"..:generate_version_cc_file",
]
sources = [
"../include/dart_api.h",
"../include/dart_debugger_api.h",
"../include/dart_mirrors_api.h",
"../include/dart_native_api.h",
"../vm/dart_api_impl.cc",
"../vm/debugger_api_impl.cc",
"../vm/mirrors_api_impl.cc",
"../vm/native_api_impl.cc",
"$target_gen_dir/../version.cc",
]
include_dirs = [
"..",
]
defines = [
"DART_SHARED_LIB",
]
}
executable("gen_snapshot") {
configs += ["../..:dart_config"]
deps = [
":libdart_withcore",
":libdart_builtin",
]
sources = [
"gen_snapshot.cc",
# Very limited native resolver provided.
"builtin_gen_snapshot.cc",
"builtin.cc",
"builtin.h",
# Include generated source files.
"$target_gen_dir/builtin_gen.cc",
"$target_gen_dir/io_gen.cc",
"$target_gen_dir/io_patch_gen.cc",
]
include_dirs = [
"..",
]
}
static_library("libdart_embedder_noio") {
configs += ["../..:dart_config",]
deps = [
"..:libdart",
"../vm:libdart_platform",
]
}

View file

@ -0,0 +1,32 @@
# Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
# for details. All rights reserved. Use of this source code is governed by a
# BSD-style license that can be found in the LICENSE file.
static_library("libdouble_conversion") {
configs += [ "../../../..:dart_config", ]
sources = [
"bignum.cc",
"bignum.h",
"bignum-dtoa.cc",
"bignum-dtoa.h",
"cached-powers.cc",
"cached-powers.h",
"diy-fp.cc",
"diy-fp.h",
"double-conversion.cc",
"double-conversion.h",
"fast-dtoa.cc",
"fast-dtoa.h",
"fixed-dtoa.cc",
"fixed-dtoa.h",
"ieee.h",
"strtod.cc",
"strtod.h",
"utils.h",
]
include_dirs = [
".",
]
}

27
runtime/third_party/jscre/BUILD.gn vendored Normal file
View file

@ -0,0 +1,27 @@
# Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
# for details. All rights reserved. Use of this source code is governed by a
# BSD-style license that can be found in the LICENSE file.
static_library("libjscre") {
configs += [ "../../..:dart_config", ]
defines = [
"SUPPORT_UTF8",
"SUPPORT_UCP",
"NO_RECURSE",
]
sources = [
"ASCIICType.h",
"config.h",
"pcre.h",
"pcre_internal.h",
"ucpinternal.h",
"pcre_compile.cpp",
"pcre_exec.cpp",
"pcre_tables.cpp",
"pcre_ucp_searchfuncs.cpp",
"pcre_xclass.cpp",
]
include_dirs = [
".",
]
}

201
runtime/vm/BUILD.gn Normal file
View file

@ -0,0 +1,201 @@
# Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
# for details. All rights reserved. Use of this source code is governed by a
# BSD-style license that can be found in the LICENSE file.
config("libdart_vm_config") {
libs = [
"pthread",
"rt",
"dl",
]
}
static_library("libdart_platform") {
configs += ["../..:dart_config"]
public_configs = [":libdart_vm_config"]
platform_headers_gypi =
exec_script("../../tools/gypi_to_gn.py",
[rebase_path("../platform/platform_headers.gypi")],
"scope",
["../platform/platform_headers.gypi"])
platform_headers =
rebase_path(platform_headers_gypi.sources, ".", "../platform")
platform_sources_gypi =
exec_script("../../tools/gypi_to_gn.py",
[rebase_path("../platform/platform_sources.gypi")],
"scope",
["../platform/platform_sources.gypi"])
platform_sources =
rebase_path(platform_sources_gypi.sources, ".", "../platform")
sources = platform_headers + platform_sources
include_dirs = [
"..",
]
}
static_library("libdart_vm") {
configs += ["../..:dart_config"]
public_configs = [":libdart_vm_config"]
deps = [ ":generate_service_cc_file", ]
vm_sources_list = exec_script("../../tools/gypi_to_gn.py",
[rebase_path("vm_sources.gypi")],
"scope",
["vm_sources.gypi"])
set_sources_assignment_filter(["*_test.cc", "*_test.h"])
sources = vm_sources_list.sources
+ ["$target_gen_dir/service_gen.cc",]
- ["vtune.cc", "vtune.h"]
include_dirs = [
"..",
]
}
template("generate_library_source") {
assert(defined(invoker.libname), "Need libname in $target_name")
assert(defined(invoker.filename), "Need a filename in $target_name")
assert(defined(invoker.kind), "Need kind in $target_name")
assert(defined(invoker.output), "Need output in $target_name")
action(target_name) {
visibility = [ ":*" ] # Only targets in this file can see this.
libname = invoker.libname
filename = invoker.filename
kind = invoker.kind
if (kind == "source") {
path = "../../sdk/lib/${filename}"
} else {
path = "../lib"
}
lib_sources_gypi =
exec_script("../../tools/gypi_to_gn.py",
[rebase_path("${path}/${filename}_sources.gypi")],
"scope",
["${path}/${filename}_sources.gypi"])
lib_sources =
rebase_path(lib_sources_gypi.sources, ".", path)
script = "../tools/gen_library_src_paths.py"
inputs = [
"../tools/gen_library_src_paths.py",
"../lib/libgen_in.cc",
]
outputs = [ invoker.output, ]
args = [
"--output", rebase_path(invoker.output, root_build_dir),
"--input_cc", rebase_path("../lib/libgen_in.cc", root_build_dir),
"--include", "vm/bootstrap.h",
"--var_name", "dart::Bootstrap::${libname}_${kind}_paths_",
"--library_name", "dart:${libname}",] +
rebase_path(lib_sources, root_build_dir)
}
}
# This templates expects invoker.sources to be a list of pairs of strings.
# The pairs of strings mean the following.
# library name, file name
# e.g. for the "internal" library named "dart:_internal",
# with sources listed at sdk/lib/internal/internal_sources.gypi and
# lib/internal_sources.gypi, we have: ["_internal", "internal"]
#
# The template iterates over the list, and generates generate_library_source
# actions for each. After that, it generates targets to compile the generated
# sources to make libdart_lib_withcore and libdart_lib.
template("generate_core_libraries") {
assert(defined(invoker.sources), "Need sources in $target_name")
liboutputs = []
libsources = []
libdeps = []
foreach(lib, invoker.sources) {
libname = lib[0]
filename = lib[1]
generate_library_source("generate_${filename}_cc_file") {
libname = libname
filename = filename
kind = "source"
output = "$target_gen_dir/${filename}_gen.cc"
}
generate_library_source("generate_${filename}_patch_cc_file") {
libname = libname
filename = filename
kind = "patch"
output = "$target_gen_dir/${filename}_patch_gen.cc"
}
lib_sources_gypi =
exec_script("../../tools/gypi_to_gn.py",
[rebase_path("../lib/${filename}_sources.gypi")],
"scope",
["../lib/${filename}_sources.gypi"])
libsources += rebase_path(lib_sources_gypi.sources, ".", "../lib")
liboutputs += ["$target_gen_dir/${filename}_gen.cc",
"$target_gen_dir/${filename}_patch_gen.cc"]
libdeps += [":generate_${filename}_cc_file",
":generate_${filename}_patch_cc_file"]
}
static_library("libdart_lib_withcore") {
configs += ["../..:dart_config"]
deps = libdeps
sources = libsources + ["bootstrap.cc"] + liboutputs
include_dirs = [
"..",
]
}
static_library("libdart_lib") {
configs += ["../..:dart_config"]
sources = libsources + [ "bootstrap_nocore.cc", ]
include_dirs = [
"..",
]
}
}
generate_core_libraries("core_libraries") {
sources = [
["async", "async"],
["core", "core"],
["collection", "collection"],
["convert", "convert"],
["_internal", "internal"],
["isolate", "isolate"],
["math", "math"],
["mirrors", "mirrors"],
["typed_data", "typed_data"],
["profiler", "profiler"],
]
}
action("generate_service_cc_file") {
visibility = [ ":*" ] # Only targets in this file can see this.
script = "../tools/create_resources.py"
sources = [
"service/client.dart",
"service/constants.dart",
"service/message.dart",
"service/message_router.dart",
"service/running_isolate.dart",
"service/running_isolates.dart",
"service/vmservice.dart",
]
output = "$target_gen_dir/service_gen.cc"
outputs = [ output, ]
args = [
"--output", rebase_path(output, root_build_dir),
"--outer_namespace", "dart",
"--table_name", "service",
"--root_prefix", rebase_path("service/", root_build_dir)] +
rebase_path(sources, root_build_dir)
}

39
tools/gn_helpers.py Normal file
View file

@ -0,0 +1,39 @@
# Copyright 2014 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""Helper functions useful when writing scripts that are run from GN's
exec_script function."""
class GNException(Exception):
pass
def ToGNString(value, allow_dicts = True):
"""Prints the given value to stdout.
allow_dicts indicates if this function will allow converting dictionaries
to GN scopes. This is only possible at the top level, you can't nest a
GN scope in a list, so this should be set to False for recursive calls."""
if isinstance(value, str):
if value.find('\n') >= 0:
raise GNException("Trying to print a string with a newline in it.")
return '"' + value.replace('"', '\\"') + '"'
if isinstance(value, list):
return '[ %s ]' % ', '.join(ToGNString(v) for v in value)
if isinstance(value, dict):
if not allow_dicts:
raise GNException("Attempting to recursively print a dictionary.")
result = ""
for key in value:
if not isinstance(key, str):
raise GNException("Dictionary key is not a string.")
result += "%s = %s\n" % (key, ToGNString(value[key], False))
return result
if isinstance(value, int):
return str(value)
raise GNException("Unsupported type when printing to GN.")

167
tools/gypi_to_gn.py Normal file
View file

@ -0,0 +1,167 @@
# Copyright 2014 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""Converts a given gypi file to a python scope and writes the result to stdout.
It is assumed that the file contains a toplevel dictionary, and this script
will return that dictionary as a GN "scope" (see example below). This script
does not know anything about GYP and it will not expand variables or execute
conditions.
It will strip conditions blocks.
A variables block at the top level will be flattened so that the variables
appear in the root dictionary. This way they can be returned to the GN code.
Say your_file.gypi looked like this:
{
'sources': [ 'a.cc', 'b.cc' ],
'defines': [ 'ENABLE_DOOM_MELON' ],
}
You would call it like this:
gypi_values = exec_script("//build/gypi_to_gn.py",
[ rebase_path("your_file.gypi") ],
"scope",
[ "your_file.gypi" ])
Notes:
- The rebase_path call converts the gypi file from being relative to the
current build file to being system absolute for calling the script, which
will have a different current directory than this file.
- The "scope" parameter tells GN to interpret the result as a series of GN
variable assignments.
- The last file argument to exec_script tells GN that the given file is a
dependency of the build so Ninja can automatically re-run GN if the file
changes.
Read the values into a target like this:
component("mycomponent") {
sources = gypi_values.sources
defines = gypi_values.defines
}
Sometimes your .gypi file will include paths relative to a different
directory than the current .gn file. In this case, you can rebase them to
be relative to the current directory.
sources = rebase_path(gypi_values.sources, ".",
"//path/gypi/input/values/are/relative/to")
This script will tolerate a 'variables' in the toplevel dictionary or not. If
the toplevel dictionary just contains one item called 'variables', it will be
collapsed away and the result will be the contents of that dictinoary. Some
.gypi files are written with or without this, depending on how they expect to
be embedded into a .gyp file.
This script also has the ability to replace certain substrings in the input.
Generally this is used to emulate GYP variable expansion. If you passed the
argument "--replace=<(foo)=bar" then all instances of "<(foo)" in strings in
the input will be replaced with "bar":
gypi_values = exec_script("//build/gypi_to_gn.py",
[ rebase_path("your_file.gypi"),
"--replace=<(foo)=bar"],
"scope",
[ "your_file.gypi" ])
"""
import gn_helpers
from optparse import OptionParser
import sys
def LoadPythonDictionary(path):
file_string = open(path).read()
try:
file_data = eval(file_string, {'__builtins__': None}, None)
except SyntaxError, e:
e.filename = path
raise
except Exception, e:
raise Exception("Unexpected error while reading %s: %s" % (path, str(e)))
assert isinstance(file_data, dict), "%s does not eval to a dictionary" % path
# Flatten any variables to the top level.
if 'variables' in file_data:
file_data.update(file_data['variables'])
del file_data['variables']
# Strip any conditions.
if 'conditions' in file_data:
del file_data['conditions']
if 'target_conditions' in file_data:
del file_data['target_conditions']
# Strip targets in the toplevel, since some files define these and we can't
# slurp them in.
if 'targets' in file_data:
del file_data['targets']
return file_data
def ReplaceSubstrings(values, search_for, replace_with):
"""Recursively replaces substrings in a value.
Replaces all substrings of the "search_for" with "repace_with" for all
strings occurring in "values". This is done by recursively iterating into
lists as well as the keys and values of dictionaries."""
if isinstance(values, str):
return values.replace(search_for, replace_with)
if isinstance(values, list):
return [ReplaceSubstrings(v, search_for, replace_with) for v in values]
if isinstance(values, dict):
# For dictionaries, do the search for both the key and values.
result = {}
for key, value in values.items():
new_key = ReplaceSubstrings(key, search_for, replace_with)
new_value = ReplaceSubstrings(value, search_for, replace_with)
result[new_key] = new_value
return result
# Assume everything else is unchanged.
return values
def main():
parser = OptionParser()
parser.add_option("-r", "--replace", action="append",
help="Replaces substrings. If passed a=b, replaces all substrs a with b.")
(options, args) = parser.parse_args()
if len(args) != 1:
raise Exception("Need one argument which is the .gypi file to read.")
data = LoadPythonDictionary(args[0])
if options.replace:
# Do replacements for all specified patterns.
for replace in options.replace:
split = replace.split('=')
# Allow "foo=" to replace with nothing.
if len(split) == 1:
split.append('')
assert len(split) == 2, "Replacement must be of the form 'key=value'."
data = ReplaceSubstrings(data, split[0], split[1])
# Sometimes .gypi files use the GYP syntax with percents at the end of the
# variable name (to indicate not to overwrite a previously-defined value):
# 'foo%': 'bar',
# Convert these to regular variables.
for key in data:
if len(key) > 1 and key[len(key) - 1] == '%':
data[key[:-1]] = data[key]
del data[key]
print gn_helpers.ToGNString(data)
if __name__ == '__main__':
try:
main()
except Exception, e:
print str(e)
sys.exit(1)