Refactor Options to support multiple inputs
Now, the single executable 'aidl' supports both Java and C++ as target
languages. The language is set via --lang={java|cpp} option. The old
'aidl-cpp' is still supported for backwards compatibility reason. When
invoked with --lang option, 'aidl' behaves as before, i.e. compile an
AIDL file into a Java file.
When --lang option is specified, one can provide multiple AIDL files as
inputs.
aidl --lang=java -o out_dir IFoo.aidl IBar.aidl
This command creates IFoo.java and IBar.java under out_dir.
aidl --lang=cpp -o out_dir -h header_dir IFoo.aidl IBar.aidl
This command creates IFoo.cpp and IBar.cpp under out_dir and the header
files under header_dir.
The input AIDL files are automatically included to the import path, so
there is no need to explicitly set include path for them.
Internally, JavaOptions and CppOptions are unified into the single
Options class, where parsing is done using getopt(3) in order to better
support long/short options, for example, include path can be set via
either of -IDIR, -I DIR, --include=DIR, and --include DIR.
Bug: 110967839
Test: runtests.py
Change-Id: I0b2f9d6b53e99f821ec04b053996f43378065437
diff --git a/Android.bp b/Android.bp
index 38b2625..7d3e00f 100644
--- a/Android.bp
+++ b/Android.bp
@@ -64,7 +64,7 @@
cc_binary_host {
name: "aidl",
defaults: ["aidl_defaults"],
- srcs: ["main_java.cpp"],
+ srcs: ["main.cpp"],
static_libs: [
"libaidl-common",
"libbase",
diff --git a/aidl.cpp b/aidl.cpp
index d8cc4b8..ff6fbdd 100644
--- a/aidl.cpp
+++ b/aidl.cpp
@@ -264,118 +264,83 @@
return err;
}
-void write_common_dep_file(const string& output_file,
- const vector<string>& aidl_sources,
- CodeWriter* writer,
- const bool ninja) {
+bool write_dep_file(const Options& options, const AidlDefinedType& defined_type,
+ const vector<unique_ptr<AidlImport>>& imports, const IoDelegate& io_delegate,
+ const string& input_file, const string& output_file) {
+ string dep_file_name = options.DependencyFile();
+ if (dep_file_name.empty() && options.AutoDepFile()) {
+ dep_file_name = output_file + ".d";
+ }
+
+ if (dep_file_name.empty()) {
+ return true; // nothing to do
+ }
+ CodeWriterPtr writer = io_delegate.GetCodeWriter(dep_file_name);
+ if (!writer) {
+ LOG(ERROR) << "Could not open dependency file: " << dep_file_name;
+ return false;
+ }
+
+ vector<string> source_aidl = {input_file};
+ for (const auto& import : imports) {
+ if (!import->GetFilename().empty()) {
+ source_aidl.push_back(import->GetFilename());
+ }
+ }
+
// Encode that the output file depends on aidl input files.
writer->Write("%s : \\\n", output_file.c_str());
- writer->Write(" %s", Join(aidl_sources, " \\\n ").c_str());
+ writer->Write(" %s", Join(source_aidl, " \\\n ").c_str());
writer->Write("\n");
- if (!ninja) {
+ if (!options.DependencyFileNinja()) {
writer->Write("\n");
// Output "<input_aidl_file>: " so make won't fail if the input .aidl file
// has been deleted, moved or renamed in incremental build.
- for (const auto& src : aidl_sources) {
+ for (const auto& src : source_aidl) {
writer->Write("%s :\n", src.c_str());
}
}
-}
-bool write_java_dep_file(const JavaOptions& options,
- const vector<unique_ptr<AidlImport>>& imports,
- const IoDelegate& io_delegate,
- const string& output_file_name) {
- string dep_file_name = options.DependencyFilePath();
- if (dep_file_name.empty()) {
- return true; // nothing to do
- }
- CodeWriterPtr writer = io_delegate.GetCodeWriter(dep_file_name);
- if (!writer) {
- LOG(ERROR) << "Could not open dependency file: " << dep_file_name;
- return false;
- }
+ if (options.TargetLanguage() == Options::Language::CPP) {
+ if (!options.DependencyFileNinja()) {
+ using ::android::aidl::cpp::ClassNames;
+ using ::android::aidl::cpp::HeaderFile;
+ vector<string> headers;
+ for (ClassNames c : {ClassNames::CLIENT, ClassNames::SERVER, ClassNames::INTERFACE}) {
+ headers.push_back(options.OutputHeaderDir() + '/' +
+ HeaderFile(defined_type, c, false /* use_os_sep */));
+ }
- vector<string> source_aidl = {options.input_file_name_};
- for (const auto& import : imports) {
- if (!import->GetFilename().empty()) {
- source_aidl.push_back(import->GetFilename());
+ writer->Write("\n");
+
+ // Generated headers also depend on the source aidl files.
+ writer->Write("%s : \\\n %s\n", Join(headers, " \\\n ").c_str(),
+ Join(source_aidl, " \\\n ").c_str());
}
}
- write_common_dep_file(output_file_name, source_aidl, writer.get(),
- options.DependencyFileNinja());
-
- return true;
-}
-
-bool write_cpp_dep_file(const CppOptions& options, const AidlDefinedType& defined_type,
- const vector<unique_ptr<AidlImport>>& imports,
- const IoDelegate& io_delegate) {
- using ::android::aidl::cpp::HeaderFile;
- using ::android::aidl::cpp::ClassNames;
-
- string dep_file_name = options.DependencyFilePath();
- if (dep_file_name.empty()) {
- return true; // nothing to do
- }
- CodeWriterPtr writer = io_delegate.GetCodeWriter(dep_file_name);
- if (!writer) {
- LOG(ERROR) << "Could not open dependency file: " << dep_file_name;
- return false;
- }
-
- vector<string> source_aidl = {options.InputFileName()};
- for (const auto& import : imports) {
- if (!import->GetFilename().empty()) {
- source_aidl.push_back(import->GetFilename());
- }
- }
-
- write_common_dep_file(options.OutputCppFilePath(), source_aidl, writer.get(),
- options.DependencyFileNinja());
-
- if (!options.DependencyFileNinja()) {
- vector<string> headers;
- for (ClassNames c : {ClassNames::CLIENT,
- ClassNames::SERVER,
- ClassNames::INTERFACE}) {
- headers.push_back(options.OutputHeaderDir() + '/' +
- HeaderFile(defined_type, c, false /* use_os_sep */));
- }
-
- writer->Write("\n");
-
- // Generated headers also depend on the source aidl files.
- writer->Write("%s : \\\n %s\n", Join(headers, " \\\n ").c_str(),
- Join(source_aidl, " \\\n ").c_str());
- }
-
return true;
}
-string generate_outputFileName(const JavaOptions& options, const AidlDefinedType& defined_type) {
- const string& name = defined_type.GetName();
- string package = defined_type.GetPackage();
- string result;
-
+string generate_outputFileName(const Options& options, const AidlDefinedType& defined_type) {
// create the path to the destination folder based on the
// defined_type package name
- result = options.output_base_folder_;
+ string result = options.OutputDir();
result += OS_PATH_SEPARATOR;
- string packageStr = package;
- size_t len = packageStr.length();
+ string package = defined_type.GetPackage();
+ size_t len = package.length();
for (size_t i = 0; i < len; i++) {
- if (packageStr[i] == '.') {
- packageStr[i] = OS_PATH_SEPARATOR;
+ if (package[i] == '.') {
+ package[i] = OS_PATH_SEPARATOR;
}
}
- result += packageStr;
+ result += package;
// add the filename by replacing the .aidl extension to .java
+ const string& name = defined_type.GetName();
result += OS_PATH_SEPARATOR;
result.append(name, 0, name.find('.'));
result += ".java";
@@ -717,78 +682,94 @@
} // namespace internals
-int compile_aidl_to_cpp(const CppOptions& options,
- const IoDelegate& io_delegate) {
- unique_ptr<AidlDefinedType> defined_type;
- std::vector<std::unique_ptr<AidlImport>> imports;
- unique_ptr<cpp::TypeNamespace> types(new cpp::TypeNamespace());
- types->Init();
- ImportResolver import_resolver{io_delegate, options.ImportPaths(), {}};
- AidlError err = internals::load_and_validate_aidl(
- options.preprocessed_files_, import_resolver, options.InputFileName(),
- options.ShouldGenTraces(), io_delegate, types.get(), &defined_type, &imports);
- if (err != AidlError::OK) {
- return 1;
+int compile_aidl_to_cpp(const Options& options, const IoDelegate& io_delegate) {
+ for (const string& input_file : options.InputFiles()) {
+ unique_ptr<AidlDefinedType> defined_type;
+ std::vector<std::unique_ptr<AidlImport>> imports;
+ unique_ptr<cpp::TypeNamespace> types(new cpp::TypeNamespace());
+ types->Init();
+ ImportResolver import_resolver{io_delegate, options.ImportPaths(), options.InputFiles()};
+ AidlError err = internals::load_and_validate_aidl(options.PreprocessedFiles(), import_resolver,
+ input_file, options.GenTraces(), io_delegate,
+ types.get(), &defined_type, &imports);
+ if (err != AidlError::OK) {
+ return 1;
+ }
+
+ CHECK(defined_type != nullptr);
+
+ string output_file_name = options.OutputFile();
+ // if needed, generate the output file name from the base folder
+ if (output_file_name.empty() && !options.OutputDir().empty()) {
+ output_file_name = options.OutputDir() + defined_type->GetName() + ".cpp";
+ }
+
+ if (!write_dep_file(options, *defined_type, imports, io_delegate, input_file,
+ output_file_name)) {
+ return 1;
+ }
+
+ bool success = cpp::GenerateCpp(output_file_name, options, *types, *defined_type, io_delegate);
+ if (!success) {
+ return 1;
+ }
}
-
- CHECK(defined_type != nullptr);
-
- if (!write_cpp_dep_file(options, *defined_type, imports, io_delegate)) {
- return 1;
- }
-
- return (cpp::GenerateCpp(options, *types, *defined_type, io_delegate)) ? 0 : 1;
+ return 0;
}
-int compile_aidl_to_java(const JavaOptions& options,
- const IoDelegate& io_delegate) {
- unique_ptr<AidlDefinedType> defined_type;
- std::vector<std::unique_ptr<AidlImport>> imports;
- unique_ptr<java::JavaTypeNamespace> types(new java::JavaTypeNamespace());
- types->Init();
- ImportResolver import_resolver{io_delegate, options.import_paths_, {}};
- AidlError aidl_err = internals::load_and_validate_aidl(
- options.preprocessed_files_, import_resolver, options.input_file_name_, options.gen_traces_,
- io_delegate, types.get(), &defined_type, &imports);
- if (aidl_err == AidlError::FOUND_PARCELABLE && !options.fail_on_parcelable_) {
- // We aborted code generation because this file contains parcelables.
- // However, we were not told to complain if we find parcelables.
- // Just generate a dep file and exit quietly. The dep file is for a legacy
- // use case by the SDK.
- write_java_dep_file(options, imports, io_delegate, "");
- return 0;
- }
- if (aidl_err != AidlError::OK) {
- return 1;
- }
+int compile_aidl_to_java(const Options& options, const IoDelegate& io_delegate) {
+ for (const string& input_file : options.InputFiles()) {
+ unique_ptr<AidlDefinedType> defined_type;
+ std::vector<std::unique_ptr<AidlImport>> imports;
+ unique_ptr<java::JavaTypeNamespace> types(new java::JavaTypeNamespace());
+ types->Init();
+ ImportResolver import_resolver{io_delegate, options.ImportPaths(), options.InputFiles()};
+ AidlError aidl_err = internals::load_and_validate_aidl(
+ options.PreprocessedFiles(), import_resolver, input_file, options.GenTraces(), io_delegate,
+ types.get(), &defined_type, &imports);
+ if (aidl_err == AidlError::FOUND_PARCELABLE && !options.FailOnParcelable()) {
+ // We aborted code generation because this file contains parcelables.
+ // However, we were not told to complain if we find parcelables.
+ // Just generate a dep file and exit quietly. The dep file is for a legacy
+ // use case by the SDK.
+ write_dep_file(options, *defined_type, imports, io_delegate, input_file, "");
+ return 0;
+ }
+ if (aidl_err != AidlError::OK) {
+ return 1;
+ }
- CHECK(defined_type != nullptr);
+ CHECK(defined_type != nullptr);
- string output_file_name = options.output_file_name_;
- // if needed, generate the output file name from the base folder
- if (output_file_name.empty() && !options.output_base_folder_.empty()) {
- output_file_name = generate_outputFileName(options, *defined_type);
+ string output_file_name = options.OutputFile();
+ // if needed, generate the output file name from the base folder
+ if (output_file_name.empty() && !options.OutputDir().empty()) {
+ output_file_name = generate_outputFileName(options, *defined_type);
+ }
+
+ // make sure the folders of the output file all exists
+ if (!io_delegate.CreatePathForFile(output_file_name)) {
+ return 1;
+ }
+
+ if (!write_dep_file(options, *defined_type, imports, io_delegate, input_file,
+ output_file_name)) {
+ return 1;
+ }
+
+ bool success = generate_java(output_file_name, input_file.c_str(), defined_type.get(),
+ types.get(), io_delegate, options);
+ if (!success) {
+ return 1;
+ }
}
-
- // make sure the folders of the output file all exists
- if (!io_delegate.CreatePathForFile(output_file_name)) {
- return 1;
- }
-
- if (!write_java_dep_file(options, imports, io_delegate, output_file_name)) {
- return 1;
- }
-
- return generate_java(output_file_name, options.input_file_name_.c_str(), defined_type.get(),
- types.get(), io_delegate, options);
+ return 0;
}
-bool preprocess_aidl(const JavaOptions& options,
- const IoDelegate& io_delegate) {
- unique_ptr<CodeWriter> writer =
- io_delegate.GetCodeWriter(options.output_file_name_);
+bool preprocess_aidl(const Options& options, const IoDelegate& io_delegate) {
+ unique_ptr<CodeWriter> writer = io_delegate.GetCodeWriter(options.OutputFile());
- for (const auto& file : options.input_file_names_) {
+ for (const auto& file : options.InputFiles()) {
AidlTypenames typenames;
Parser p{io_delegate, &typenames};
if (!p.ParseFile(file))
@@ -807,16 +788,16 @@
return writer->Close();
}
-bool dump_api(const JavaOptions& options, const IoDelegate& io_delegate) {
- ImportResolver import_resolver{io_delegate, options.import_paths_, options.input_file_names_};
+bool dump_api(const Options& options, const IoDelegate& io_delegate) {
+ ImportResolver import_resolver{io_delegate, options.ImportPaths(), options.InputFiles()};
map<string, vector<unique_ptr<AidlDefinedType>>> types_by_package;
- for (const auto& file : options.input_file_names_) {
+ for (const auto& file : options.InputFiles()) {
unique_ptr<java::JavaTypeNamespace> types(new java::JavaTypeNamespace());
types->Init();
unique_ptr<AidlDefinedType> t;
- if (internals::load_and_validate_aidl(options.preprocessed_files_, import_resolver, file,
- options.gen_traces_, io_delegate, types.get(), &t,
+ if (internals::load_and_validate_aidl(options.PreprocessedFiles(), import_resolver, file,
+ options.GenTraces(), io_delegate, types.get(), &t,
nullptr) == AidlError::OK) {
// group them by package name
string package = t->GetPackage();
@@ -835,7 +816,7 @@
}
// print
- unique_ptr<CodeWriter> writer = io_delegate.GetCodeWriter(options.output_file_name_);
+ unique_ptr<CodeWriter> writer = io_delegate.GetCodeWriter(options.OutputFile());
for (auto it = types_by_package.begin(); it != types_by_package.end(); it++) {
writer->Write("package %s {\n", it->first.c_str());
writer->Indent();
diff --git a/aidl.h b/aidl.h
index c464132..c87150e 100644
--- a/aidl.h
+++ b/aidl.h
@@ -46,13 +46,10 @@
OK = 0,
};
-int compile_aidl_to_cpp(const CppOptions& options,
- const IoDelegate& io_delegate);
-int compile_aidl_to_java(const JavaOptions& options,
- const IoDelegate& io_delegate);
-bool preprocess_aidl(const JavaOptions& options,
- const IoDelegate& io_delegate);
-bool dump_api(const JavaOptions& options, const IoDelegate& io_delegate);
+int compile_aidl_to_cpp(const Options& options, const IoDelegate& io_delegate);
+int compile_aidl_to_java(const Options& options, const IoDelegate& io_delegate);
+bool preprocess_aidl(const Options& options, const IoDelegate& io_delegate);
+bool dump_api(const Options& options, const IoDelegate& io_delegate);
namespace internals {
diff --git a/aidl_unittest.cpp b/aidl_unittest.cpp
index 4cc0904..e1a4952 100644
--- a/aidl_unittest.cpp
+++ b/aidl_unittest.cpp
@@ -221,11 +221,11 @@
io_delegate_.SetFileContents("one/IBar.aidl", "package one; import p.Outer;"
"interface IBar {}");
- JavaOptions options;
- options.output_file_name_ = "preprocessed";
- options.input_file_names_.resize(2);
- options.input_file_names_[0] = "p/Outer.aidl";
- options.input_file_names_[1] = "one/IBar.aidl";
+ Options options;
+ options.output_file_ = "preprocessed";
+ options.input_files_.resize(2);
+ options.input_files_[0] = "p/Outer.aidl";
+ options.input_files_[1] = "one/IBar.aidl";
EXPECT_TRUE(::android::aidl::preprocess_aidl(options, io_delegate_));
string output;
@@ -259,10 +259,9 @@
}
TEST_F(AidlTest, FailOnParcelable) {
- JavaOptions options;
- options.input_file_name_ = "p/IFoo.aidl";
- io_delegate_.SetFileContents(options.input_file_name_,
- "package p; parcelable IFoo;");
+ Options options;
+ options.input_files_.push_back("p/IFoo.aidl");
+ io_delegate_.SetFileContents(options.input_files_.front(), "package p; parcelable IFoo;");
// By default, we shouldn't fail on parcelable.
EXPECT_EQ(0, ::android::aidl::compile_aidl_to_java(options, io_delegate_));
options.fail_on_parcelable_ = true;
@@ -410,16 +409,14 @@
// While the in tree build system always gives us an output file name,
// other android tools take advantage of our ability to infer the intended
// file name. This test makes sure we handle this correctly.
- JavaOptions options;
- options.input_file_name_ = "p/IFoo.aidl";
- options.output_base_folder_ = "place/for/output";
- options.dep_file_name_ = "dep/file/path";
- io_delegate_.SetFileContents(options.input_file_name_,
- "package p; interface IFoo {}");
+ Options options;
+ options.input_files_.push_back("p/IFoo.aidl");
+ options.output_dir_ = "place/for/output";
+ options.dependency_file_ = "dep/file/path";
+ io_delegate_.SetFileContents(options.input_files_.front(), "package p; interface IFoo {}");
EXPECT_EQ(0, ::android::aidl::compile_aidl_to_java(options, io_delegate_));
string actual_dep_file_contents;
- EXPECT_TRUE(io_delegate_.GetWrittenContents(options.dep_file_name_,
- &actual_dep_file_contents));
+ EXPECT_TRUE(io_delegate_.GetWrittenContents(options.dependency_file_, &actual_dep_file_contents));
EXPECT_EQ(actual_dep_file_contents, kExpectedDepFileContents);
}
@@ -427,17 +424,15 @@
// While the in tree build system always gives us an output file name,
// other android tools take advantage of our ability to infer the intended
// file name. This test makes sure we handle this correctly.
- JavaOptions options;
- options.input_file_name_ = "p/IFoo.aidl";
- options.output_base_folder_ = "place/for/output";
- options.dep_file_name_ = "dep/file/path";
- options.dep_file_ninja_ = true;
- io_delegate_.SetFileContents(options.input_file_name_,
- "package p; interface IFoo {}");
+ Options options;
+ options.input_files_.push_back("p/IFoo.aidl");
+ options.output_dir_ = "place/for/output";
+ options.dependency_file_ = "dep/file/path";
+ options.dependency_file_ninja_ = true;
+ io_delegate_.SetFileContents(options.input_files_.front(), "package p; interface IFoo {}");
EXPECT_EQ(0, ::android::aidl::compile_aidl_to_java(options, io_delegate_));
string actual_dep_file_contents;
- EXPECT_TRUE(io_delegate_.GetWrittenContents(options.dep_file_name_,
- &actual_dep_file_contents));
+ EXPECT_TRUE(io_delegate_.GetWrittenContents(options.dependency_file_, &actual_dep_file_contents));
EXPECT_EQ(actual_dep_file_contents, kExpectedNinjaDepFileContents);
}
@@ -447,16 +442,14 @@
// generated dependency files. Those that reference .java output files are
// for interfaces and those that do not are parcelables. However, for both
// parcelables and interfaces, we *must* generate a non-empty dependency file.
- JavaOptions options;
- options.input_file_name_ = "p/Foo.aidl";
- options.output_base_folder_ = "place/for/output";
- options.dep_file_name_ = "dep/file/path";
- io_delegate_.SetFileContents(options.input_file_name_,
- "package p; parcelable Foo;");
+ Options options;
+ options.input_files_.push_back("p/Foo.aidl");
+ options.output_dir_ = "place/for/output";
+ options.dependency_file_ = "dep/file/path";
+ io_delegate_.SetFileContents(options.input_files_.front(), "package p; parcelable Foo;");
EXPECT_EQ(0, ::android::aidl::compile_aidl_to_java(options, io_delegate_));
string actual_dep_file_contents;
- EXPECT_TRUE(io_delegate_.GetWrittenContents(options.dep_file_name_,
- &actual_dep_file_contents));
+ EXPECT_TRUE(io_delegate_.GetWrittenContents(options.dependency_file_, &actual_dep_file_contents));
EXPECT_EQ(actual_dep_file_contents, kExpectedParcelableDepFileContents);
}
@@ -495,9 +488,9 @@
" List<foo.bar.IFoo> b;\n"
"}\n");
io_delegate_.SetFileContents("api.aidl", "");
- JavaOptions options;
- options.input_file_names_ = {"foo/bar/IFoo.aidl", "foo/bar/Data.aidl"};
- options.output_file_name_ = "api.aidl";
+ Options options;
+ options.input_files_ = {"foo/bar/IFoo.aidl", "foo/bar/Data.aidl"};
+ options.output_file_ = "api.aidl";
bool result = dump_api(options, io_delegate_);
ASSERT_TRUE(result);
string actual;
diff --git a/generate_cpp.cpp b/generate_cpp.cpp
index e74ec40..c37fd7e 100644
--- a/generate_cpp.cpp
+++ b/generate_cpp.cpp
@@ -936,11 +936,8 @@
NestInNamespaces(std::move(file_decls), parcel.GetSplitPackage())}};
}
-bool WriteHeader(const CppOptions& options,
- const TypeNamespace& types,
- const AidlInterface& interface,
- const IoDelegate& io_delegate,
- ClassNames header_type) {
+bool WriteHeader(const Options& options, const TypeNamespace& types, const AidlInterface& interface,
+ const IoDelegate& io_delegate, ClassNames header_type) {
unique_ptr<Document> header;
switch (header_type) {
case ClassNames::INTERFACE:
@@ -993,8 +990,9 @@
return file_path;
}
-bool GenerateCppInterface(const CppOptions& options, const TypeNamespace& types,
- const AidlInterface& interface, const IoDelegate& io_delegate) {
+bool GenerateCppInterface(const string& output_file, const Options& options,
+ const TypeNamespace& types, const AidlInterface& interface,
+ const IoDelegate& io_delegate) {
auto interface_src = BuildInterfaceSource(types, interface);
auto client_src = BuildClientSource(types, interface);
auto server_src = BuildServerSource(types, interface);
@@ -1018,22 +1016,22 @@
return false;
}
- unique_ptr<CodeWriter> writer = io_delegate.GetCodeWriter(
- options.OutputCppFilePath());
+ unique_ptr<CodeWriter> writer = io_delegate.GetCodeWriter(output_file);
interface_src->Write(writer.get());
client_src->Write(writer.get());
server_src->Write(writer.get());
const bool success = writer->Close();
if (!success) {
- io_delegate.RemovePath(options.OutputCppFilePath());
+ io_delegate.RemovePath(options.OutputFile());
}
return success;
}
-bool GenerateCppParcel(const CppOptions& options, const cpp::TypeNamespace& types,
- const AidlStructuredParcelable& parcelable, const IoDelegate& io_delegate) {
+bool GenerateCppParcel(const string& output_file, const Options& options,
+ const cpp::TypeNamespace& types, const AidlStructuredParcelable& parcelable,
+ const IoDelegate& io_delegate) {
auto header = BuildParcelHeader(types, parcelable);
auto source = BuildParcelSource(types, parcelable);
@@ -1063,23 +1061,23 @@
bn_writer->Write("#error TODO(b/111362593) parcelables do not have bn classes");
CHECK(bn_writer->Close());
- unique_ptr<CodeWriter> source_writer = io_delegate.GetCodeWriter(options.OutputCppFilePath());
+ unique_ptr<CodeWriter> source_writer = io_delegate.GetCodeWriter(output_file);
source->Write(source_writer.get());
CHECK(source_writer->Close());
return true;
}
-bool GenerateCpp(const CppOptions& options, const TypeNamespace& types,
+bool GenerateCpp(const string& output_file, const Options& options, const TypeNamespace& types,
const AidlDefinedType& defined_type, const IoDelegate& io_delegate) {
const AidlStructuredParcelable* parcelable = defined_type.AsStructuredParcelable();
if (parcelable != nullptr) {
- return GenerateCppParcel(options, types, *parcelable, io_delegate);
+ return GenerateCppParcel(output_file, options, types, *parcelable, io_delegate);
}
const AidlInterface* interface = defined_type.AsInterface();
if (interface != nullptr) {
- return GenerateCppInterface(options, types, *interface, io_delegate);
+ return GenerateCppInterface(output_file, options, types, *interface, io_delegate);
}
CHECK(false) << "Unrecognized type sent for cpp generation.";
diff --git a/generate_cpp.h b/generate_cpp.h
index b6215b0..9b09198 100644
--- a/generate_cpp.h
+++ b/generate_cpp.h
@@ -29,7 +29,7 @@
namespace aidl {
namespace cpp {
-bool GenerateCpp(const CppOptions& options, const cpp::TypeNamespace& types,
+bool GenerateCpp(const string& output_file, const Options& options, const cpp::TypeNamespace& types,
const AidlDefinedType& parsed_doc, const IoDelegate& io_delegate);
// These roughly correspond to the various class names in the C++ hierarchy:
diff --git a/generate_cpp_unittest.cpp b/generate_cpp_unittest.cpp
index 86f5706..b4b89a8 100644
--- a/generate_cpp_unittest.cpp
+++ b/generate_cpp_unittest.cpp
@@ -1511,17 +1511,17 @@
"package a; interface IFoo {}"),
options_(GetOptions()) {}
- const unique_ptr<CppOptions> options_;
+ const unique_ptr<Options> options_;
private:
- static unique_ptr<CppOptions> GetOptions() {
+ static unique_ptr<Options> GetOptions() {
using namespace test_io_handling;
const int argc = 4;
const char* cmdline[argc] = {
"aidl-cpp", kInputPath, kHeaderDir, kOutputPath
};
- return CppOptions::Parse(argc, cmdline);
+ return unique_ptr<Options>(new Options(argc, cmdline, Options::Language::CPP));
}
};
@@ -1529,7 +1529,7 @@
// Confirm that this is working correctly without I/O problems.
const unique_ptr<AidlInterface> interface = ParseInterface();
ASSERT_NE(interface, nullptr);
- ASSERT_TRUE(GenerateCpp(*options_, types_, *interface, io_delegate_));
+ ASSERT_TRUE(GenerateCpp(options_->OutputFile(), *options_, types_, *interface, io_delegate_));
}
TEST_F(IoErrorHandlingTest, HandlesBadHeaderWrite) {
@@ -1542,7 +1542,7 @@
StringPrintf("%s%c%s", kHeaderDir, OS_PATH_SEPARATOR,
kInterfaceHeaderRelPath);
io_delegate_.AddBrokenFilePath(header_path);
- ASSERT_FALSE(GenerateCpp(*options_, types_, *interface, io_delegate_));
+ ASSERT_FALSE(GenerateCpp(options_->OutputFile(), *options_, types_, *interface, io_delegate_));
// We should never attempt to write the C++ file if we fail writing headers.
ASSERT_FALSE(io_delegate_.GetWrittenContents(kOutputPath, nullptr));
// We should remove partial results.
@@ -1556,7 +1556,7 @@
// Simulate issues closing the cpp file.
io_delegate_.AddBrokenFilePath(kOutputPath);
- ASSERT_FALSE(GenerateCpp(*options_, types_, *interface, io_delegate_));
+ ASSERT_FALSE(GenerateCpp(options_->OutputFile(), *options_, types_, *interface, io_delegate_));
// We should remove partial results.
ASSERT_TRUE(io_delegate_.PathWasRemoved(kOutputPath));
}
diff --git a/generate_java.cpp b/generate_java.cpp
index 30951a8..41b51a0 100644
--- a/generate_java.cpp
+++ b/generate_java.cpp
@@ -55,9 +55,9 @@
namespace java {
-int generate_java_interface(const string& filename, const string& original_src,
- const AidlInterface* iface, JavaTypeNamespace* types,
- const IoDelegate& io_delegate, const JavaOptions& options) {
+bool generate_java_interface(const string& filename, const string& original_src,
+ const AidlInterface* iface, JavaTypeNamespace* types,
+ const IoDelegate& io_delegate, const Options& options) {
Class* cl = generate_binder_interface_class(iface, types, options);
Document* document =
@@ -66,12 +66,12 @@
CodeWriterPtr code_writer = io_delegate.GetCodeWriter(filename);
document->Write(code_writer.get());
- return 0;
+ return true;
}
-int generate_java_parcel(const std::string& filename, const std::string& original_src,
- const AidlStructuredParcelable* parcel, JavaTypeNamespace* types,
- const IoDelegate& io_delegate, const JavaOptions& options) {
+bool generate_java_parcel(const std::string& filename, const std::string& original_src,
+ const AidlStructuredParcelable* parcel, JavaTypeNamespace* types,
+ const IoDelegate& io_delegate, const Options& options) {
Class* cl = generate_parcel_class(parcel, types, options);
Document* document =
@@ -80,12 +80,12 @@
CodeWriterPtr code_writer = io_delegate.GetCodeWriter(filename);
document->Write(code_writer.get());
- return 0;
+ return true;
}
-int generate_java(const std::string& filename, const std::string& original_src,
- const AidlDefinedType* defined_type, JavaTypeNamespace* types,
- const IoDelegate& io_delegate, const JavaOptions& options) {
+bool generate_java(const std::string& filename, const std::string& original_src,
+ const AidlDefinedType* defined_type, JavaTypeNamespace* types,
+ const IoDelegate& io_delegate, const Options& options) {
const AidlStructuredParcelable* parcelable = defined_type->AsStructuredParcelable();
if (parcelable != nullptr) {
return generate_java_parcel(filename, original_src, parcelable, types, io_delegate, options);
@@ -102,7 +102,7 @@
android::aidl::java::Class* generate_parcel_class(const AidlStructuredParcelable* parcel,
java::JavaTypeNamespace* types,
- const JavaOptions& /*options*/) {
+ const Options& /*options*/) {
const ParcelType* parcelType = parcel->GetLanguageType<ParcelType>();
Class* parcel_class = new Class;
diff --git a/generate_java.h b/generate_java.h
index 680a199..beb421c 100644
--- a/generate_java.h
+++ b/generate_java.h
@@ -26,23 +26,23 @@
namespace android {
namespace aidl {
-class JavaOptions;
+class Options;
namespace java {
class JavaTypeNamespace;
-int generate_java(const std::string& filename, const std::string& original_src,
- const AidlDefinedType* iface, java::JavaTypeNamespace* types,
- const IoDelegate& io_delegate, const JavaOptions& options);
+bool generate_java(const std::string& filename, const std::string& original_src,
+ const AidlDefinedType* iface, java::JavaTypeNamespace* types,
+ const IoDelegate& io_delegate, const Options& options);
-android::aidl::java::Class* generate_binder_interface_class(
- const AidlInterface* iface, java::JavaTypeNamespace* types,
- const JavaOptions& options);
+android::aidl::java::Class* generate_binder_interface_class(const AidlInterface* iface,
+ java::JavaTypeNamespace* types,
+ const Options& options);
android::aidl::java::Class* generate_parcel_class(const AidlStructuredParcelable* parcel,
java::JavaTypeNamespace* types,
- const JavaOptions& options);
+ const Options& options);
} // namespace java
diff --git a/generate_java_binder.cpp b/generate_java_binder.cpp
index 09e0f33..6a45df5 100644
--- a/generate_java_binder.cpp
+++ b/generate_java_binder.cpp
@@ -42,8 +42,8 @@
// =================================================
class StubClass : public Class {
public:
- StubClass(const Type* type, const InterfaceType* interfaceType,
- JavaTypeNamespace* types, const JavaOptions& options);
+ StubClass(const Type* type, const InterfaceType* interfaceType, JavaTypeNamespace* types,
+ const Options& options);
virtual ~StubClass() = default;
Variable* transact_code;
@@ -72,13 +72,13 @@
JavaTypeNamespace* types);
Variable* transact_descriptor;
- const JavaOptions& options_;
+ const Options& options_;
DISALLOW_COPY_AND_ASSIGN(StubClass);
};
-StubClass::StubClass(const Type* type, const InterfaceType* interfaceType,
- JavaTypeNamespace* types, const JavaOptions& options)
+StubClass::StubClass(const Type* type, const InterfaceType* interfaceType, JavaTypeNamespace* types,
+ const Options& options)
: Class(), options_(options) {
transact_descriptor = nullptr;
transact_outline = false;
@@ -125,7 +125,7 @@
this->elements.push_back(asBinder);
// getTransactionName
- if (options_.ShouldGenGetTransactionName()) {
+ if (options_.GenTransactionNames()) {
Method* getTransactionName = new Method;
getTransactionName->modifiers = PUBLIC;
getTransactionName->returnType = types->StringType();
@@ -170,7 +170,7 @@
transact_statements->Add(this->transact_switch);
// getTransactionName
- if (options_.ShouldGenGetTransactionName()) {
+ if (options_.GenTransactionNames()) {
// Some transaction codes are common, e.g. INTERFACE_TRANSACTION or DUMP_TRANSACTION.
// Common transaction codes will not be resolved to a string by getTransactionName. The method
// will return NULL in this case.
@@ -714,14 +714,9 @@
return proxy;
}
-static void generate_methods(const AidlInterface& iface,
- const AidlMethod& method,
- Class* interface,
- StubClass* stubClass,
- ProxyClass* proxyClass,
- int index,
- JavaTypeNamespace* types,
- const JavaOptions& options) {
+static void generate_methods(const AidlInterface& iface, const AidlMethod& method, Class* interface,
+ StubClass* stubClass, ProxyClass* proxyClass, int index,
+ JavaTypeNamespace* types, const Options& options) {
const bool oneway = proxyClass->mOneWay || method.IsOneway();
// == the TRANSACT_ constant =============================================
@@ -735,7 +730,7 @@
stubClass->elements.push_back(transactCode);
// getTransactionName
- if (options.ShouldGenGetTransactionName()) {
+ if (options.GenTransactionNames()) {
Case* c = new Case(transactCodeName);
c->statements->Add(new ReturnStatement(new StringLiteralExpression(method.GetName())));
stubClass->code_to_method_name_switch->cases.push_back(c);
@@ -873,9 +868,8 @@
return default_class;
}
-Class* generate_binder_interface_class(const AidlInterface* iface,
- JavaTypeNamespace* types,
- const JavaOptions& options) {
+Class* generate_binder_interface_class(const AidlInterface* iface, JavaTypeNamespace* types,
+ const Options& options) {
const InterfaceType* interfaceType = iface->GetLanguageType<InterfaceType>();
// the interface class
diff --git a/main.cpp b/main.cpp
new file mode 100644
index 0000000..739bc47
--- /dev/null
+++ b/main.cpp
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2015, 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.
+ */
+
+#include "aidl.h"
+#include "io_delegate.h"
+#include "logging.h"
+#include "options.h"
+
+#include <iostream>
+#include <memory>
+
+using android::aidl::Options;
+
+// aidl is leaky. Turn off LeakSanitizer by default. b/37749857
+extern "C" const char* __asan_default_options() {
+ return "detect_leaks=0";
+}
+
+int main(int argc, char* argv[]) {
+ android::base::InitLogging(argv);
+ LOG(DEBUG) << "aidl starting";
+ Options options(argc, argv, Options::Language::JAVA);
+ if (!options.Ok()) {
+ std::cerr << options.GetErrorMessage();
+ std::cerr << options.GetUsage();
+ return 1;
+ }
+
+ android::aidl::IoDelegate io_delegate;
+ Options::Language lang = options.TargetLanguage();
+ switch (options.GetTask()) {
+ case Options::Task::COMPILE:
+ if (lang == Options::Language::JAVA) {
+ return android::aidl::compile_aidl_to_java(options, io_delegate);
+ } else if (lang == Options::Language::CPP) {
+ return android::aidl::compile_aidl_to_cpp(options, io_delegate);
+ }
+ case Options::Task::PREPROCESS:
+ if (android::aidl::preprocess_aidl(options, io_delegate)) return 0;
+ return 1;
+ case Options::Task::DUMPAPI:
+ return android::aidl::dump_api(options, io_delegate);
+ default:
+ LOG(FATAL) << "aidl: internal error" << std::endl;
+ return 1;
+ }
+}
diff --git a/main_cpp.cpp b/main_cpp.cpp
index e904a92..3454eca 100644
--- a/main_cpp.cpp
+++ b/main_cpp.cpp
@@ -14,29 +14,31 @@
* limitations under the License.
*/
-#include <memory>
-
#include "aidl.h"
#include "io_delegate.h"
#include "logging.h"
#include "options.h"
-using android::aidl::CppOptions;
+#include <iostream>
+
+using android::aidl::Options;
// aidl is leaky. Turn off LeakSanitizer by default. b/37749857
extern "C" const char *__asan_default_options() {
return "detect_leaks=0";
}
-int main(int argc, char** argv) {
+int main(int argc, char* argv[]) {
android::base::InitLogging(argv);
LOG(DEBUG) << "aidl starting";
- std::unique_ptr<CppOptions> options = CppOptions::Parse(argc, argv);
- if (!options) {
+ Options options(argc, argv, Options::Language::CPP);
+ if (!options.Ok()) {
+ std::cerr << options.GetErrorMessage();
+ std::cerr << options.GetUsage();
return 1;
}
android::aidl::IoDelegate io_delegate;
- return android::aidl::compile_aidl_to_cpp(*options, io_delegate);
+ return android::aidl::compile_aidl_to_cpp(options, io_delegate);
}
diff --git a/main_java.cpp b/main_java.cpp
deleted file mode 100644
index aaf8423..0000000
--- a/main_java.cpp
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright (C) 2015, 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.
- */
-
-#include <iostream>
-#include <memory>
-
-#include "aidl.h"
-#include "io_delegate.h"
-#include "logging.h"
-#include "options.h"
-
-using android::aidl::JavaOptions;
-
-// aidl is leaky. Turn off LeakSanitizer by default. b/37749857
-extern "C" const char *__asan_default_options() {
- return "detect_leaks=0";
-}
-
-int main(int argc, char** argv) {
- android::base::InitLogging(argv);
- LOG(DEBUG) << "aidl starting";
- std::unique_ptr<JavaOptions> options = JavaOptions::Parse(argc, argv);
- if (!options) {
- return 1;
- }
-
- android::aidl::IoDelegate io_delegate;
- switch (options->task) {
- case JavaOptions::COMPILE_AIDL_TO_JAVA:
- return android::aidl::compile_aidl_to_java(*options, io_delegate);
- case JavaOptions::PREPROCESS_AIDL:
- if (android::aidl::preprocess_aidl(*options, io_delegate))
- return 0;
- return 1;
- case JavaOptions::DUMP_API:
- return android::aidl::dump_api(*options, io_delegate);
- }
- std::cerr << "aidl: internal error" << std::endl;
- return 1;
-}
diff --git a/options.cpp b/options.cpp
index 6b03c19..d7bbadd 100644
--- a/options.cpp
+++ b/options.cpp
@@ -16,305 +16,287 @@
#include "options.h"
-#include <cstring>
+#include <getopt.h>
+#include <stdlib.h>
+#include <unistd.h>
#include <iostream>
-#include <stdio.h>
+#include <sstream>
+#include <string>
-#include "logging.h"
-#include "os.h"
+#include <android-base/strings.h>
-using std::cerr;
+using android::base::Trim;
using std::endl;
using std::string;
-using std::unique_ptr;
-using std::vector;
namespace android {
namespace aidl {
-Options::Result Options::ParseFlag(int index, const std::string& arg) {
- if (arg.size() < 2) return Result::UNHANDLED;
- if (arg[0] != '-') return Result::UNHANDLED;
-
- if (arg[1] == 'I') {
- if (arg.size() > 2) {
- this->import_paths_.push_back(arg.substr(2));
- return Result::CONSUMED;
- } else {
- fprintf(stderr, "-I option (%d) requires a path.\n", index);
- return Result::ERROR;
- }
- }
-
- if (arg[1] == 'd') {
- if (arg.size() > 2) {
- this->dep_file_name_ = arg.substr(2);
- return Result::CONSUMED;
- } else {
- fprintf(stderr, "-d option (%d) requires a file.\n", index);
- return Result::ERROR;
- }
- }
-
- if (arg == "--ninja") {
- this->dep_file_ninja_ = true;
- return Result::CONSUMED;
- }
-
- if (arg == "-t") {
- this->gen_traces_ = true;
- return Result::CONSUMED;
- }
-
- if (arg[1] == 'p') {
- if (arg.size() > 2) {
- this->preprocessed_files_.push_back(arg.substr(2));
- return Result::CONSUMED;
- } else {
- fprintf(stderr, "-p option (%d) requires a file.\n", index);
- return Result::ERROR;
- }
- }
-
- return Result::UNHANDLED;
-}
-
-void Options::FlagUsage() {
- cerr << " -I<DIR> search path for import statements" << endl
- << " -p<FILE> file created by --preprocess to import." << endl
- << " -d<FILE> generate dependency file" << endl
- << " -t include tracing code for systrace. Note that if the client or server code "
- "is not auto-generated by this tool, that part will not be traced."
+string Options::GetUsage() const {
+ std::ostringstream sstr;
+ sstr << "usage:" << endl
+ << myname_ << " --lang={java|cpp} [OPTION]... INPUT..." << endl
+ << " Generate Java or C++ files for AIDL file(s)." << endl
<< endl
- << " --ninja generate dependency file in a format ninja understands" << endl;
-}
-
-unique_ptr<JavaOptions> JavaOptions::Usage() {
- fprintf(stderr,
- "usage: aidl OPTIONS INPUT [OUTPUT]\n"
- " aidl --preprocess OUTPUT INPUT...\n"
- " aidl --dumpapi OUTPUT INPUT...\n"
- "\n"
- "OPTIONS:\n");
- this->FlagUsage();
- fprintf(stderr,
- "\n"
- "INPUT:\n"
- " An aidl interface file.\n"
- "\n"
- "OUTPUT:\n"
- " The generated interface files.\n"
- " If omitted and the -o option is not used, the input filename is "
- "used, with the .aidl extension changed to a .java extension.\n"
- " If the -o option is used, the generated files will be placed in "
- "the base output folder, under their package folder\n");
- return unique_ptr<JavaOptions>(nullptr);
-}
-
-Options::Result JavaOptions::ParseFlag(int index, const std::string& arg) {
- Result parent = Options::ParseFlag(index, arg);
- if (parent != Result::UNHANDLED) return parent;
-
- if (arg.size() < 2) return Result::UNHANDLED;
- if (arg[0] != '-') return Result::UNHANDLED;
-
- if (arg == "-a") {
- this->auto_dep_file_ = true;
- return Result::CONSUMED;
- }
-
- if (arg[1] == 'o') {
- if (arg.size() > 2) {
- this->output_base_folder_ = arg.substr(2);
- return Result::CONSUMED;
- } else {
- fprintf(stderr, "-o option (%d) requires a path.\n", index);
- return Result::ERROR;
- }
- }
-
- if (arg == "-b") {
- this->fail_on_parcelable_ = true;
- return Result::CONSUMED;
- }
-
- if (arg == "--transaction_names") {
- this->gen_transaction_names_ = true;
- return Result::CONSUMED;
- }
-
- return Result::UNHANDLED;
-}
-
-void JavaOptions::FlagUsage() {
- Options::FlagUsage();
- cerr << " -a generate dependency file next to the output file with the name based on "
- "the input file."
+ << myname_ << " --preprocess OUTPUT INPUT..." << endl
+ << " Create an AIDL file having declarations of AIDL file(s)." << endl
<< endl
- << " -o<FOLDER> base output folder for generated files." << endl
- << " -b fail when trying to compile a parcelable." << endl
- << " --transaction_names generate method to resolve a binder method code to the original "
- "method name."
+ << myname_ << " --dumpapi OUTPUT INPUT..." << endl
+ << " Dump API signature of AIDL file(s)." << endl
<< endl;
-}
-unique_ptr<JavaOptions> JavaOptions::Parse(int argc, const char* const* argv) {
- unique_ptr<JavaOptions> options(new JavaOptions());
- int i = 1;
-
- if (argc >= 2) {
- if (argc < 4) {
- return options->Usage();
- }
- options->output_file_name_ = argv[2];
- for (int i = 3; i < argc; i++) {
- options->input_file_names_.push_back(argv[i]);
- }
- if (0 == strcmp(argv[1], "--preprocess")) {
- options->task = PREPROCESS_AIDL;
- return options;
- } else if (0 == strcmp(argv[1], "--dumpapi")) {
- options->task = DUMP_API;
- return options;
- }
+ // Legacy option formats
+ if (language_ == Options::Language::JAVA) {
+ sstr << myname_ << " [OPTION]... INPUT [OUTPUT]" << endl
+ << " Generate a Java file for an AIDL file." << endl
+ << endl;
+ } else if (language_ == Options::Language::CPP) {
+ sstr << myname_ << " [OPTION]... INPUT HEADER_DIR OUTPUT" << endl
+ << " Generate C++ headers and source for an AIDL file." << endl
+ << endl;
}
- options->task = COMPILE_AIDL_TO_JAVA;
- // OPTIONS
- for (; i < argc; i++) {
- const char* s = argv[i];
-
- Result res = options->ParseFlag(i, s);
- if (res == Result::ERROR) return options->Usage();
- if (res == Result::UNHANDLED) {
- if (s[0] == '-') {
- cerr << "unknown option (" << i << "): " << s << endl;
- return options->Usage();
- }
- break; // On to the positional arguments
- }
- CHECK(res == Result::CONSUMED);
- }
- // INPUT
- if (i < argc) {
- options->input_file_name_ = argv[i];
- i++;
- } else {
- fprintf(stderr, "INPUT required\n");
- return options->Usage();
- }
- if (!EndsWith(options->input_file_name_, ".aidl")) {
- cerr << "Expected .aidl file for input but got "
- << options->input_file_name_ << endl;
- return options->Usage();
- }
-
- // OUTPUT
- if (i < argc) {
- options->output_file_name_ = argv[i];
- i++;
- } else if (options->output_base_folder_.empty()) {
- // copy input into output and change the extension from .aidl to .java
- options->output_file_name_= options->input_file_name_;
- if (!ReplaceSuffix(".aidl", ".java", &options->output_file_name_)) {
- // we should never get here since we validated the suffix.
- LOG(FATAL) << "Internal aidl error.";
- return options->Usage();
- }
- }
-
- // anything remaining?
- if (i != argc) {
- fprintf(stderr, "unknown option%s:",
- (i == argc - 1 ? (const char*)"" : (const char*)"s"));
- for (; i < argc - 1; i++) {
- fprintf(stderr, " %s", argv[i]);
- }
- fprintf(stderr, "\n");
- return options->Usage();
- }
-
- return options;
-}
-
-string JavaOptions::DependencyFilePath() const {
- if (auto_dep_file_) {
- return output_file_name_ + ".d";
- }
- return dep_file_name_;
-}
-
-unique_ptr<CppOptions> CppOptions::Usage() {
- cerr << "usage: aidl-cpp INPUT_FILE HEADER_DIR OUTPUT_FILE" << endl << endl << "OPTIONS:" << endl;
- this->FlagUsage();
- cerr << endl
- << "INPUT_FILE:" << endl
- << " an aidl interface file" << endl
+ sstr << "OPTION:" << endl
+ << " -I DIR, --include=DIR" << endl
+ << " Use DIR as a search path for import statements." << endl
+ << " -p FILE, --preprocessed=FILE" << endl
+ << " Include FILE which is created by --preprocess." << endl
+ << " -d FILE, --dep=FILE" << endl
+ << " Generate dependency file as FILE. Don't use this when" << endl
+ << " there are multiple input files. Use -a then." << endl
+ << " -o DIR, --out=DIR" << endl
+ << " Use DIR as the base output directory for generated files." << endl
+ << " -h DIR, --header_out=DIR" << endl
+ << " Generate C++ headers under DIR." << endl
+ << " -a" << endl
+ << " Generate dependency file next to the output file with the" << endl
+ << " name based on the input file." << endl
+ << " -b" << endl
+ << " Trigger fail when trying to compile a parcelable." << endl
+ << " --ninja" << endl
+ << " Generate dependency file in a format ninja understands." << endl
+ << " -t, --trace" << endl
+ << " Include tracing code for systrace. Note that if either" << endl
+ << " the client or service code is not auto-generated by this" << endl
+ << " tool, that part will not be traced." << endl
+ << " --transaction_names" << endl
+ << " Generate transaction names." << endl
+ << " --help" << endl
+ << " Show this help." << endl
+ << endl
+ << "INPUT:" << endl
+ << " An AIDL file." << endl
+ << endl
+ << "OUTPUT:" << endl
+ << " Path to the generated Java or C++ source file. This is ignored when" << endl
+ << " -o or --out is specified or the number of the input files are" << endl
+ << " more than one." << endl
+ << " For Java, if omitted, Java source file is generated at the same" << endl
+ << " place as the input AIDL file," << endl
+ << endl
<< "HEADER_DIR:" << endl
- << " empty directory to put generated headers" << endl
- << "OUTPUT_FILE:" << endl
- << " path to write generated .cpp code" << endl;
- return unique_ptr<CppOptions>(nullptr);
+ << " Path to where C++ headers are generated." << endl;
+ return sstr.str();
}
-unique_ptr<CppOptions> CppOptions::Parse(int argc, const char* const* argv) {
- unique_ptr<CppOptions> options(new CppOptions());
- int i = 1;
-
- // Parse flags, all of which start with '-'
- for ( ; i < argc; ++i) {
- const char *s = argv[i];
-
- Result res = options->ParseFlag(i, s);
- if (res == Result::ERROR) return options->Usage();
- if (res == Result::UNHANDLED) {
- if (s[0] == '-') {
- cerr << "unknown option (" << i << "): " << s << endl;
- return options->Usage();
- }
- break; // On to the positional arguments
+Options::Options(int argc, const char* const argv[], Options::Language default_lang)
+ : myname_(argv[0]), language_(default_lang) {
+ bool lang_option_found = false;
+ optind = 1;
+ while (true) {
+ static struct option long_options[] = {
+ {"lang", required_argument, 0, 'l'},
+ {"preprocess", no_argument, 0, 's'},
+ {"dumpapi", no_argument, 0, 'u'},
+ {"include", required_argument, 0, 'I'},
+ {"preprocessed", required_argument, 0, 'p'},
+ {"dep", required_argument, 0, 'd'},
+ {"out", required_argument, 0, 'o'},
+ {"header_out", required_argument, 0, 'h'},
+ {"ninja", no_argument, 0, 'n'},
+ {"trace", no_argument, 0, 't'},
+ {"transaction_names", no_argument, 0, 'c'},
+ {"help", no_argument, 0, 'e'},
+ {0, 0, 0, 0},
+ };
+ const int c =
+ getopt_long(argc, const_cast<char* const*>(argv), "I:p:d:o:h:abt", long_options, nullptr);
+ if (c == -1) {
+ // no more options
+ break;
}
- CHECK(res == Result::CONSUMED);
+
+ switch (c) {
+ case 'l':
+ if (language_ == Options::Language::CPP) {
+ // aidl-cpp can't set language. aidl-cpp exists only for backwards
+ // compatibility.
+ error_message_ << "aidl-cpp does not support --lang." << endl;
+ return;
+ } else {
+ lang_option_found = true;
+ string lang = Trim(string(optarg));
+ if (lang == "java") {
+ language_ = Options::Language::JAVA;
+ task_ = Options::Task::COMPILE;
+ } else if (lang == "cpp") {
+ language_ = Options::Language::CPP;
+ task_ = Options::Task::COMPILE;
+ } else {
+ error_message_ << "Unsupported language: '" << lang << "'" << endl;
+ return;
+ }
+ }
+ break;
+ case 's':
+ if (task_ != Options::Task::UNSPECIFIED) {
+ task_ = Options::Task::PREPROCESS;
+ }
+ break;
+ case 'u':
+ if (task_ != Options::Task::UNSPECIFIED) {
+ task_ = Options::Task::DUMPAPI;
+ }
+ break;
+ case 'I':
+ import_paths_.emplace_back(Trim(string(optarg)));
+ break;
+ case 'p':
+ preprocessed_files_.emplace_back(Trim(string(optarg)));
+ break;
+ case 'd':
+ dependency_file_ = Trim(string(optarg));
+ break;
+ case 'o':
+ output_dir_ = Trim(string(optarg));
+ break;
+ case 'h':
+ output_header_dir_ = Trim(string(optarg));
+ break;
+ case 'n':
+ dependency_file_ninja_ = true;
+ break;
+ case 't':
+ gen_traces_ = true;
+ break;
+ case 'a':
+ auto_dep_file_ = true;
+ break;
+ case 'b':
+ fail_on_parcelable_ = true;
+ break;
+ case 'c':
+ gen_transaction_names_ = true;
+ break;
+ case 'e':
+ std::cerr << GetUsage();
+ exit(0);
+ default:
+ error_message_ << "Invalid argument: '" << argv[optind] << "'" << endl;
+ return;
+ }
+ } // while
+
+ // Positional arguments
+ if (!lang_option_found && task_ == Options::Task::COMPILE) {
+ // the legacy arguments format
+ if (argc - optind <= 0) {
+ error_message_ << "No input file" << endl;
+ return;
+ }
+ if (language_ == Options::Language::JAVA) {
+ input_files_.emplace_back(argv[optind++]);
+ if (argc - optind >= 1) {
+ output_file_ = argv[optind++];
+ } else {
+ // when output is omitted, output is by default set to the input
+ // file path with .aidl is replaced to .java.
+ output_file_ = input_files_.front();
+ output_file_.replace(output_file_.length() - strlen(".aidl"), strlen(".aidl"), ".java");
+ }
+ } else if (language_ == Options::Language::CPP) {
+ input_files_.emplace_back(argv[optind++]);
+ if (argc - optind < 2) {
+ error_message_ << "No HEADER_DIR or OUTPUT." << endl;
+ return;
+ }
+ output_header_dir_ = argv[optind++];
+ output_file_ = argv[optind++];
+ }
+ if (argc - optind > 0) {
+ error_message_ << "Too many arguments: ";
+ for (int i = optind; i < argc; i++) {
+ error_message_ << " " << argv[i];
+ }
+ error_message_ << endl;
+ }
+ return;
+ } else {
+ // the new arguments format
+ if (task_ == Options::Task::COMPILE) {
+ if (argc - optind < 1) {
+ error_message_ << "No input file." << endl;
+ return;
+ }
+ } else {
+ if (argc - optind < 2) {
+ error_message_ << "Insufficient arguments. At least 2 required, but "
+ << "got " << (argc - optind) << "." << endl;
+ return;
+ }
+ output_file_ = argv[optind++];
+ }
+ while (optind < argc) {
+ input_files_.emplace_back(argv[optind++]);
+ }
}
- // There are exactly three positional arguments.
- const int remaining_args = argc - i;
- if (remaining_args != 3) {
- cerr << "Expected 3 positional arguments but got " << remaining_args << "." << endl;
- return options->Usage();
+ // filter out invalid combinations
+ for (const string& input : input_files_) {
+ if (!android::base::EndsWith(input, ".aidl")) {
+ error_message_ << "Expected .aidl file for input but got '" << input << "'" << endl;
+ return;
+ }
+ }
+ if (language_ == Options::Language::CPP && task_ == Options::Task::COMPILE) {
+ if (output_dir_.empty()) {
+ error_message_ << "Output directory is not set. Set with --out." << endl;
+ return;
+ }
+ if (output_header_dir_.empty()) {
+ error_message_ << "Header output directory is not set. Set with "
+ << "--header_out." << endl;
+ return;
+ }
+ }
+ if (language_ == Options::Language::JAVA && task_ == Options::Task::COMPILE) {
+ if (output_dir_.empty()) {
+ error_message_ << "Output directory is not set. Set with --out." << endl;
+ return;
+ }
+ if (!output_header_dir_.empty()) {
+ error_message_ << "Header output directory is set, which does not make "
+ << "sense for Java." << endl;
+ return;
+ }
+ }
+ if (task_ == Options::Task::COMPILE) {
+ if (!output_file_.empty() && input_files_.size() > 1) {
+ error_message_ << "Multiple AIDL files can't be compiled to a single "
+ << "output file '" << output_file_ << "'. "
+ << "Use --out=DIR instead for output files." << endl;
+ return;
+ }
+ if (!dependency_file_.empty() && input_files_.size() > 1) {
+ error_message_ << "-d or --dep doesn't work when compiling multiple AIDL "
+ << "files. Use '-a' to generate dependency file next to "
+ << "the output file with the name based on the input "
+ << "file." << endl;
+ return;
+ }
}
- options->input_file_name_ = argv[i];
- options->output_header_dir_ = argv[i + 1];
- options->output_file_name_ = argv[i + 2];
-
- if (!EndsWith(options->input_file_name_, ".aidl")) {
- cerr << "Expected .aidl file for input but got " << options->input_file_name_ << endl;
- return options->Usage();
- }
-
- return options;
}
-bool EndsWith(const string& str, const string& suffix) {
- if (str.length() < suffix.length()) {
- return false;
- }
- return std::equal(str.crbegin(), str.crbegin() + suffix.length(),
- suffix.crbegin());
-}
-
-bool ReplaceSuffix(const string& old_suffix,
- const string& new_suffix,
- string* str) {
- if (!EndsWith(*str, old_suffix)) return false;
- str->replace(str->length() - old_suffix.length(),
- old_suffix.length(),
- new_suffix);
- return true;
-}
-
-
-
} // namespace android
} // namespace aidl
diff --git a/options.h b/options.h
index 964109f..ced9903 100644
--- a/options.h
+++ b/options.h
@@ -16,76 +16,71 @@
#ifndef AIDL_OPTIONS_H_
#define AIDL_OPTIONS_H_
-#include <memory>
+#include <sstream>
#include <string>
#include <vector>
-#include <android-base/macros.h>
#include <gtest/gtest_prod.h>
+using std::string;
+using std::vector;
+
namespace android {
namespace aidl {
-class Options {
+class Options final {
public:
- virtual ~Options() = default;
+ enum class Language { UNSPECIFIED, JAVA, CPP };
- // flag arguments
- std::vector<std::string> import_paths_;
- std::vector<std::string> preprocessed_files_;
- std::string dep_file_name_;
- bool gen_traces_{false};
- bool dep_file_ninja_{false};
+ enum class Task { UNSPECIFIED, COMPILE, PREPROCESS, DUMPAPI };
- // positional arguments
- std::string input_file_name_;
- std::string output_file_name_;
- // currently, this is only for --dumpapi
- std::vector<std::string> input_file_names_;
+ Options(int argc, const char* const argv[], Language default_lang = Language::UNSPECIFIED);
- protected:
- enum class Result {
- CONSUMED,
- UNHANDLED,
- ERROR,
- };
+ Language TargetLanguage() const { return language_; }
- // parses all flag arguments
- virtual Result ParseFlag(int index, const std::string& arg);
+ Task GetTask() const { return task_; }
- // print all flag arguments
- virtual void FlagUsage();
-};
+ const vector<string>& ImportPaths() const { return import_paths_; }
-// This object represents the parsed options to the Java generating aidl.
-class JavaOptions final : public Options {
- public:
- enum {
- COMPILE_AIDL_TO_JAVA,
- PREPROCESS_AIDL,
- DUMP_API,
- };
+ const vector<string>& PreprocessedFiles() const { return preprocessed_files_; }
- // Parses the command line and returns a non-null pointer to an JavaOptions
- // object on success.
- // Prints the usage statement on failure.
- static std::unique_ptr<JavaOptions> Parse(int argc, const char* const* argv);
+ string DependencyFile() const {
+ if (auto_dep_file_) {
+ return output_file_ + ".d";
+ }
+ return dependency_file_;
+ }
- std::string DependencyFilePath() const;
- bool DependencyFileNinja() const { return dep_file_ninja_; }
- bool ShouldGenGetTransactionName() const { return gen_transaction_names_; }
+ bool AutoDepFile() const { return auto_dep_file_; }
- Result ParseFlag(int index, const std::string& arg) override;
- void FlagUsage() override;
+ bool GenTraces() const { return gen_traces_; }
- // flag arguments
- int task{COMPILE_AIDL_TO_JAVA};
- bool fail_on_parcelable_{false};
- bool auto_dep_file_{false};
- bool gen_transaction_names_{false}; // for Binder#getTransactionName
+ bool GenTransactionNames() const { return gen_transaction_names_; }
- // positional arguments
- std::string output_base_folder_;
+ bool DependencyFileNinja() const { return dependency_file_ninja_; }
+
+ const vector<string>& InputFiles() const { return input_files_; }
+
+ // Path to the output file. This is used only when there is only one
+ // output file for the invocation. When there are multiple outputs
+ // (e.g. compile multiple AIDL files), output files are created under
+ // OutputDir().
+ const string& OutputFile() const { return output_file_; }
+
+ // Path to the directory where output file(s) will be generated under.
+ const string& OutputDir() const { return output_dir_; }
+
+ // Path to the directory where header file(s) will be generated under.
+ // Only used when TargetLanguage() == Language::CPP
+ const string& OutputHeaderDir() const { return output_header_dir_; }
+
+ bool FailOnParcelable() const { return fail_on_parcelable_; }
+
+ bool Ok() const { return error_message_.str().empty(); }
+
+ string GetErrorMessage() const { return error_message_.str(); }
+
+ string GetUsage() const;
// The following are for testability, but cannot be influenced on the command line.
// Threshold of interface methods to enable outlining of onTransact cases.
@@ -94,9 +89,24 @@
size_t onTransact_non_outline_count_{275u};
private:
- JavaOptions() = default;
+ Options() = default;
- std::unique_ptr<JavaOptions> Usage();
+ const string myname_;
+ Language language_ = Language::UNSPECIFIED;
+ Task task_ = Task::COMPILE;
+ vector<string> import_paths_;
+ vector<string> preprocessed_files_;
+ string dependency_file_;
+ bool gen_traces_ = false;
+ bool gen_transaction_names_ = false;
+ bool dependency_file_ninja_ = false;
+ string output_dir_;
+ string output_header_dir_;
+ bool fail_on_parcelable_ = false;
+ bool auto_dep_file_ = false;
+ vector<string> input_files_;
+ string output_file_;
+ std::ostringstream error_message_;
FRIEND_TEST(EndToEndTest, IExampleInterface);
FRIEND_TEST(EndToEndTest, IExampleInterface_WithTransactionNames);
@@ -108,42 +118,8 @@
FRIEND_TEST(AidlTest, WritesCorrectDependencyFileNinja);
FRIEND_TEST(AidlTest, WritesTrivialDependencyFileForParcelable);
FRIEND_TEST(AidlTest, ApiDump);
-
- DISALLOW_COPY_AND_ASSIGN(JavaOptions);
};
-class CppOptions final : public Options {
- public:
- // Parses the command line and returns a non-null pointer to an CppOptions
- // object on success.
- // Prints the usage statement on failure.
- static std::unique_ptr<CppOptions> Parse(int argc, const char* const* argv);
-
- std::string InputFileName() const { return input_file_name_; }
- std::string OutputHeaderDir() const { return output_header_dir_; }
- std::string OutputCppFilePath() const { return output_file_name_; }
-
- std::vector<std::string> ImportPaths() const { return import_paths_; }
- std::string DependencyFilePath() const { return dep_file_name_; }
- bool DependencyFileNinja() const { return dep_file_ninja_; }
- bool ShouldGenTraces() const { return gen_traces_; }
-
- private:
- CppOptions() = default;
-
- std::unique_ptr<CppOptions> Usage();
-
- std::string output_header_dir_;
-
- FRIEND_TEST(CppOptionsTests, ParsesCompileCpp);
- FRIEND_TEST(CppOptionsTests, ParsesCompileCppNinja);
- DISALLOW_COPY_AND_ASSIGN(CppOptions);
-};
-
-bool EndsWith(const std::string& str, const std::string& suffix);
-bool ReplaceSuffix(const std::string& old_suffix,
- const std::string& new_suffix,
- std::string* str);
} // namespace android
} // namespace aidl
diff --git a/options_unittest.cpp b/options_unittest.cpp
index 71e5880..b8b95d4 100644
--- a/options_unittest.cpp
+++ b/options_unittest.cpp
@@ -14,14 +14,15 @@
* limitations under the License.
*/
+#include "options.h"
+
#include <iostream>
+#include <memory>
#include <string>
#include <vector>
#include <gtest/gtest.h>
-#include "options.h"
-
using std::cerr;
using std::endl;
using std::string;
@@ -33,9 +34,9 @@
namespace {
const char kPreprocessCommandOutputFile[] = "output_file_name";
-const char kPreprocessCommandInput1[] = "input1";
-const char kPreprocessCommandInput2[] = "input2";
-const char kPreprocessCommandInput3[] = "input3";
+const char kPreprocessCommandInput1[] = "input1.aidl";
+const char kPreprocessCommandInput2[] = "input2.aidl";
+const char kPreprocessCommandInput3[] = "input3.aidl";
const char* kPreprocessCommand[] = {
"aidl", "--preprocess",
kPreprocessCommandOutputFile,
@@ -89,119 +90,190 @@
nullptr,
};
-template <typename T>
-unique_ptr<T> GetOptions(const char* command[]) {
+unique_ptr<Options> GetOptions(const char* command[],
+ Options::Language default_lang = Options::Language::JAVA) {
int argc = 0;
const char** command_part = command;
for (; *command_part; ++argc, ++command_part) {}
- unique_ptr<T> options(T::Parse(argc, command));
- if (!options) {
+ unique_ptr<Options> ret(new Options(argc, command, default_lang));
+ if (!ret->Ok()) {
+ cerr << ret->GetErrorMessage();
cerr << "Failed to parse command line:";
for (int i = 0; i < argc; ++i) {
cerr << " " << command[i];
cerr << endl;
}
}
- EXPECT_NE(options, nullptr) << "Failed to parse options!";
- return options;
+ EXPECT_NE(ret, nullptr) << "Failed to parse options!";
+ return ret;
}
} // namespace
-TEST(JavaOptionsTests, ParsesPreprocess) {
- unique_ptr<JavaOptions> options = GetOptions<JavaOptions>(kPreprocessCommand);
- EXPECT_EQ(JavaOptions::PREPROCESS_AIDL, options->task);
- EXPECT_EQ(false, options->fail_on_parcelable_);
- EXPECT_EQ(0u, options->import_paths_.size());
- EXPECT_EQ(0u, options->preprocessed_files_.size());
- EXPECT_EQ(string{}, options->input_file_name_);
- EXPECT_EQ(string{kPreprocessCommandOutputFile}, options->output_file_name_);
- EXPECT_EQ(false, options->auto_dep_file_);
+TEST(OptionsTests, ParsesPreprocess) {
+ unique_ptr<Options> options = GetOptions(kPreprocessCommand);
+ EXPECT_EQ(Options::Task::PREPROCESS, options->GetTask());
+ EXPECT_EQ(false, options->FailOnParcelable());
+ EXPECT_EQ(0u, options->ImportPaths().size());
+ EXPECT_EQ(0u, options->PreprocessedFiles().size());
+ EXPECT_EQ(string{kPreprocessCommandOutputFile}, options->OutputFile());
+ EXPECT_EQ(false, options->AutoDepFile());
const vector<string> expected_input{kPreprocessCommandInput1,
kPreprocessCommandInput2,
kPreprocessCommandInput3};
- EXPECT_EQ(expected_input, options->input_file_names_);
+ EXPECT_EQ(expected_input, options->InputFiles());
}
-TEST(JavaOptionsTests, ParsesCompileJava) {
- unique_ptr<JavaOptions> options =
- GetOptions<JavaOptions>(kCompileJavaCommand);
- EXPECT_EQ(JavaOptions::COMPILE_AIDL_TO_JAVA, options->task);
- EXPECT_EQ(true, options->fail_on_parcelable_);
- EXPECT_EQ(1u, options->import_paths_.size());
- EXPECT_EQ(0u, options->preprocessed_files_.size());
- EXPECT_EQ(string{kCompileCommandInput}, options->input_file_name_);
- EXPECT_EQ(string{kCompileCommandJavaOutput}, options->output_file_name_);
- EXPECT_EQ(false, options->auto_dep_file_);
+TEST(OptionsTests, ParsesCompileJava) {
+ unique_ptr<Options> options = GetOptions(kCompileJavaCommand);
+ EXPECT_EQ(Options::Task::COMPILE, options->GetTask());
+ EXPECT_EQ(Options::Language::JAVA, options->TargetLanguage());
+ EXPECT_EQ(true, options->FailOnParcelable());
+ EXPECT_EQ(1u, options->ImportPaths().size());
+ EXPECT_EQ(0u, options->PreprocessedFiles().size());
+ EXPECT_EQ(string{kCompileCommandInput}, options->InputFiles().front());
+ EXPECT_EQ(string{kCompileCommandJavaOutput}, options->OutputFile());
+ EXPECT_EQ(false, options->AutoDepFile());
EXPECT_EQ(false, options->DependencyFileNinja());
}
-TEST(JavaOptionsTests, ParsesCompileJavaNinja) {
- unique_ptr<JavaOptions> options =
- GetOptions<JavaOptions>(kCompileJavaCommandNinja);
- EXPECT_EQ(JavaOptions::COMPILE_AIDL_TO_JAVA, options->task);
- EXPECT_EQ(true, options->fail_on_parcelable_);
- EXPECT_EQ(1u, options->import_paths_.size());
- EXPECT_EQ(0u, options->preprocessed_files_.size());
- EXPECT_EQ(string{kCompileCommandInput}, options->input_file_name_);
- EXPECT_EQ(string{kCompileCommandJavaOutput}, options->output_file_name_);
- EXPECT_EQ(false, options->auto_dep_file_);
+TEST(OptionsTests, ParsesCompileJavaNinja) {
+ unique_ptr<Options> options = GetOptions(kCompileJavaCommandNinja);
+ EXPECT_EQ(Options::Task::COMPILE, options->GetTask());
+ EXPECT_EQ(Options::Language::JAVA, options->TargetLanguage());
+ EXPECT_EQ(true, options->FailOnParcelable());
+ EXPECT_EQ(1u, options->ImportPaths().size());
+ EXPECT_EQ(0u, options->PreprocessedFiles().size());
+ EXPECT_EQ(string{kCompileCommandInput}, options->InputFiles().front());
+ EXPECT_EQ(string{kCompileCommandJavaOutput}, options->OutputFile());
+ EXPECT_EQ(false, options->AutoDepFile());
EXPECT_EQ(true, options->DependencyFileNinja());
}
-TEST(CppOptionsTests, ParsesCompileCpp) {
- unique_ptr<CppOptions> options = GetOptions<CppOptions>(kCompileCppCommand);
- ASSERT_EQ(1u, options->import_paths_.size());
- EXPECT_EQ(string{kCompileCommandIncludePath}.substr(2),
- options->import_paths_[0]);
- EXPECT_EQ(string{kCompileDepFile}.substr(2), options->dep_file_name_);
+TEST(OptionsTests, ParsesCompileCpp) {
+ unique_ptr<Options> options = GetOptions(kCompileCppCommand, Options::Language::CPP);
+ ASSERT_EQ(1u, options->ImportPaths().size());
+ EXPECT_EQ(string{kCompileCommandIncludePath}.substr(2), options->ImportPaths()[0]);
+ EXPECT_EQ(string{kCompileDepFile}.substr(2), options->DependencyFile());
EXPECT_EQ(false, options->DependencyFileNinja());
- EXPECT_EQ(kCompileCommandInput, options->InputFileName());
+ EXPECT_EQ(kCompileCommandInput, options->InputFiles().front());
EXPECT_EQ(kCompileCommandHeaderDir, options->OutputHeaderDir());
- EXPECT_EQ(kCompileCommandCppOutput, options->OutputCppFilePath());
+ EXPECT_EQ(kCompileCommandCppOutput, options->OutputFile());
}
-TEST(CppOptionsTests, ParsesCompileCppNinja) {
- unique_ptr<CppOptions> options = GetOptions<CppOptions>(kCompileCppCommandNinja);
- ASSERT_EQ(1u, options->import_paths_.size());
- EXPECT_EQ(string{kCompileCommandIncludePath}.substr(2),
- options->import_paths_[0]);
- EXPECT_EQ(string{kCompileDepFile}.substr(2), options->dep_file_name_);
+TEST(OptionsTests, ParsesCompileCppNinja) {
+ unique_ptr<Options> options = GetOptions(kCompileCppCommandNinja, Options::Language::CPP);
+ ASSERT_EQ(1u, options->ImportPaths().size());
+ EXPECT_EQ(string{kCompileCommandIncludePath}.substr(2), options->ImportPaths()[0]);
+ EXPECT_EQ(string{kCompileDepFile}.substr(2), options->DependencyFile());
EXPECT_EQ(true, options->DependencyFileNinja());
- EXPECT_EQ(kCompileCommandInput, options->InputFileName());
+ EXPECT_EQ(kCompileCommandInput, options->InputFiles().front());
EXPECT_EQ(kCompileCommandHeaderDir, options->OutputHeaderDir());
- EXPECT_EQ(kCompileCommandCppOutput, options->OutputCppFilePath());
+ EXPECT_EQ(kCompileCommandCppOutput, options->OutputFile());
}
-TEST(OptionsTests, EndsWith) {
- EXPECT_TRUE(EndsWith("foo", ""));
- EXPECT_TRUE(EndsWith("foo", "o"));
- EXPECT_TRUE(EndsWith("foo", "foo"));
- EXPECT_FALSE(EndsWith("foo", "fooo"));
- EXPECT_FALSE(EndsWith("", "o"));
- EXPECT_TRUE(EndsWith("", ""));
+TEST(OptionsTests, ParsesCompileJavaMultiInput) {
+ const char* argv[] = {
+ "aidl",
+ "--lang=java",
+ kCompileCommandIncludePath,
+ "-o src_out",
+ "directory/input1.aidl",
+ "directory/input2.aidl",
+ "directory/input3.aidl",
+ nullptr,
+ };
+ unique_ptr<Options> options = GetOptions(argv);
+ EXPECT_EQ(Options::Task::COMPILE, options->GetTask());
+ EXPECT_EQ(Options::Language::JAVA, options->TargetLanguage());
+ EXPECT_EQ(false, options->FailOnParcelable());
+ EXPECT_EQ(1u, options->ImportPaths().size());
+ EXPECT_EQ(0u, options->PreprocessedFiles().size());
+ const vector<string> expected_input{"directory/input1.aidl", "directory/input2.aidl",
+ "directory/input3.aidl"};
+ EXPECT_EQ(expected_input, options->InputFiles());
+ EXPECT_EQ(string{""}, options->OutputFile());
+ EXPECT_EQ(false, options->AutoDepFile());
+ EXPECT_EQ(false, options->DependencyFileNinja());
+ EXPECT_EQ(string{""}, options->OutputHeaderDir());
+ EXPECT_EQ(string{"src_out"}, options->OutputDir());
}
-TEST(OptionsTests, ReplaceSuffix) {
- struct test_case_t {
- const char* input;
- const char* old_suffix;
- const char* new_suffix;
- const char* result;
+TEST(OptionsTests, ParsesCompileJavaInvalid) {
+ // -o option is required
+ const char* arg_with_no_out_dir[] = {
+ "aidl",
+ "--lang=java",
+ kCompileCommandIncludePath,
+ "directory/input1.aidl",
+ "directory/input2.aidl",
+ "directory/input3.aidl",
+ nullptr,
};
- const size_t kNumCases = 3;
- test_case_t kTestInput[kNumCases] = {
- {"foo.bar", "bar", "foo", "foo.foo"},
- {"whole", "whole", "new", "new"},
- {"", "", "", ""},
+ EXPECT_EQ(false, GetOptions(arg_with_no_out_dir)->Ok());
+
+ // -h options is not for Java
+ const char* arg_with_header_dir[] = {
+ "aidl", "--lang=java", kCompileCommandIncludePath, "-o src_out",
+ "-h header_out", "directory/input1.aidl", "directory/input2.aidl", "directory/input3.aidl",
+ nullptr,
};
- for (const auto& test_case : kTestInput) {
- string mutated = test_case.input;
- EXPECT_TRUE(ReplaceSuffix(test_case.old_suffix,
- test_case.new_suffix,
- &mutated));
- EXPECT_EQ(mutated, test_case.result);
- }
+ EXPECT_EQ(false, GetOptions(arg_with_header_dir)->Ok());
+}
+
+TEST(OptionsTests, ParsesCompileCppMultiInput) {
+ const char* argv[] = {
+ "aidl",
+ "--lang=cpp",
+ kCompileCommandIncludePath,
+ "-h header_out",
+ "-o src_out",
+ "directory/input1.aidl",
+ "directory/input2.aidl",
+ "directory/input3.aidl",
+ nullptr,
+ };
+ unique_ptr<Options> options = GetOptions(argv);
+ EXPECT_EQ(Options::Task::COMPILE, options->GetTask());
+ EXPECT_EQ(Options::Language::CPP, options->TargetLanguage());
+ EXPECT_EQ(false, options->FailOnParcelable());
+ EXPECT_EQ(1u, options->ImportPaths().size());
+ EXPECT_EQ(0u, options->PreprocessedFiles().size());
+ const vector<string> expected_input{"directory/input1.aidl", "directory/input2.aidl",
+ "directory/input3.aidl"};
+ EXPECT_EQ(expected_input, options->InputFiles());
+ EXPECT_EQ(string{""}, options->OutputFile());
+ EXPECT_EQ(false, options->AutoDepFile());
+ EXPECT_EQ(false, options->DependencyFileNinja());
+ EXPECT_EQ(string{"header_out"}, options->OutputHeaderDir());
+ EXPECT_EQ(string{"src_out"}, options->OutputDir());
+}
+
+TEST(OptionsTests, ParsesCompileCppInvalid) {
+ // -o option is required
+ const char* arg_with_no_out_dir[] = {
+ "aidl",
+ "--lang=cpp",
+ kCompileCommandIncludePath,
+ "directory/input1.aidl",
+ "directory/input2.aidl",
+ "directory/input3.aidl",
+ nullptr,
+ };
+ EXPECT_EQ(false, GetOptions(arg_with_no_out_dir)->Ok());
+
+ // -h options is required as well
+ const char* arg_with_no_header_dir[] = {
+ "aidl",
+ "--lang=cpp",
+ kCompileCommandIncludePath,
+ "-o src_out",
+ "directory/input1.aidl",
+ "directory/input2.aidl",
+ "directory/input3.aidl",
+ nullptr,
+ };
+ EXPECT_EQ(false, GetOptions(arg_with_no_header_dir)->Ok());
}
} // namespace android
diff --git a/tests/end_to_end_tests.cpp b/tests/end_to_end_tests.cpp
index f2ff658..cd87e97 100644
--- a/tests/end_to_end_tests.cpp
+++ b/tests/end_to_end_tests.cpp
@@ -73,15 +73,15 @@
TEST_F(EndToEndTest, IExampleInterface) {
using namespace ::android::aidl::test_data::example_interface;
- JavaOptions options;
+ Options options;
options.fail_on_parcelable_ = true;
options.import_paths_.push_back("");
- options.input_file_name_ = CanonicalNameToPath(kCanonicalName, ".aidl");
- options.output_file_name_ = kJavaOutputPath;
- options.dep_file_name_ = "an/arbitrary/path/to/deps.P";
+ options.input_files_.push_back(CanonicalNameToPath(kCanonicalName, ".aidl"));
+ options.output_file_ = kJavaOutputPath;
+ options.dependency_file_ = "an/arbitrary/path/to/deps.P";
// Load up our fake file system with data.
- io_delegate_.SetFileContents(options.input_file_name_, kInterfaceDefinition);
+ io_delegate_.SetFileContents(options.input_files_.front(), kInterfaceDefinition);
io_delegate_.AddCompoundParcelable("android.test.CompoundParcelable",
{"Subclass1", "Subclass2"});
AddStubAidls(kImportedParcelables, kImportedInterfaces);
@@ -89,22 +89,22 @@
// Check that we parse correctly.
EXPECT_EQ(android::aidl::compile_aidl_to_java(options, io_delegate_), 0);
CheckFileContents(kJavaOutputPath, kExpectedJavaOutput);
- CheckFileContents(options.DependencyFilePath(), kExpectedJavaDepsOutput);
+ CheckFileContents(options.DependencyFile(), kExpectedJavaDepsOutput);
}
TEST_F(EndToEndTest, IExampleInterface_WithTrace) {
using namespace ::android::aidl::test_data::example_interface;
- JavaOptions options;
+ Options options;
options.fail_on_parcelable_ = true;
options.import_paths_.push_back("");
- options.input_file_name_ = CanonicalNameToPath(kCanonicalName, ".aidl");
- options.output_file_name_ = kJavaOutputPath;
- options.dep_file_name_ = "an/arbitrary/path/to/deps.P";
+ options.input_files_.push_back(CanonicalNameToPath(kCanonicalName, ".aidl"));
+ options.output_file_ = kJavaOutputPath;
+ options.dependency_file_ = "an/arbitrary/path/to/deps.P";
options.gen_traces_ = true;
// Load up our fake file system with data.
- io_delegate_.SetFileContents(options.input_file_name_, kInterfaceDefinition);
+ io_delegate_.SetFileContents(options.input_files_.front(), kInterfaceDefinition);
io_delegate_.AddCompoundParcelable("android.test.CompoundParcelable",
{"Subclass1", "Subclass2"});
AddStubAidls(kImportedParcelables, kImportedInterfaces);
@@ -112,22 +112,22 @@
// Check that we parse correctly.
EXPECT_EQ(android::aidl::compile_aidl_to_java(options, io_delegate_), 0);
CheckFileContents(kJavaOutputPath, kExpectedJavaOutputWithTrace);
- CheckFileContents(options.DependencyFilePath(), kExpectedJavaDepsOutput);
+ CheckFileContents(options.DependencyFile(), kExpectedJavaDepsOutput);
}
TEST_F(EndToEndTest, IExampleInterface_WithTransactionNames) {
using namespace ::android::aidl::test_data::example_interface;
- JavaOptions options;
+ Options options;
options.fail_on_parcelable_ = true;
options.import_paths_.push_back("");
- options.input_file_name_ = CanonicalNameToPath(kCanonicalName, ".aidl");
- options.output_file_name_ = kJavaOutputPath;
- options.dep_file_name_ = "an/arbitrary/path/to/deps.P";
+ options.input_files_.push_back(CanonicalNameToPath(kCanonicalName, ".aidl"));
+ options.output_file_ = kJavaOutputPath;
+ options.dependency_file_ = "an/arbitrary/path/to/deps.P";
options.gen_transaction_names_ = true;
// Load up our fake file system with data.
- io_delegate_.SetFileContents(options.input_file_name_, kInterfaceDefinition);
+ io_delegate_.SetFileContents(options.input_files_.front(), kInterfaceDefinition);
io_delegate_.AddCompoundParcelable("android.test.CompoundParcelable",
{"Subclass1", "Subclass2"});
AddStubAidls(kImportedParcelables, kImportedInterfaces);
@@ -135,23 +135,23 @@
// Check that we parse correctly.
EXPECT_EQ(android::aidl::compile_aidl_to_java(options, io_delegate_), 0);
CheckFileContents(kJavaOutputPath, kExpectedJavaOutputWithTransactionNames);
- CheckFileContents(options.DependencyFilePath(), kExpectedJavaDepsOutput);
+ CheckFileContents(options.DependencyFile(), kExpectedJavaDepsOutput);
}
TEST_F(EndToEndTest, IExampleInterface_Outlining) {
using namespace ::android::aidl::test_data::example_interface;
- JavaOptions options;
+ Options options;
options.fail_on_parcelable_ = true;
options.import_paths_.push_back("");
- options.input_file_name_ = CanonicalNameToPath(kCanonicalName, ".aidl");
- options.output_file_name_ = kJavaOutputPath;
- options.dep_file_name_ = "an/arbitrary/path/to/deps.P";
+ options.input_files_.push_back(CanonicalNameToPath(kCanonicalName, ".aidl"));
+ options.output_file_ = kJavaOutputPath;
+ options.dependency_file_ = "an/arbitrary/path/to/deps.P";
options.onTransact_outline_threshold_ = 4;
options.onTransact_non_outline_count_ = 3;
// Load up our fake file system with data.
- io_delegate_.SetFileContents(options.input_file_name_, kInterfaceDefinitionOutlining);
+ io_delegate_.SetFileContents(options.input_files_.front(), kInterfaceDefinitionOutlining);
io_delegate_.AddCompoundParcelable("android.test.CompoundParcelable",
{"Subclass1", "Subclass2"});
AddStubAidls(kImportedParcelables, kImportedInterfaces);
@@ -159,7 +159,7 @@
// Check that we parse correctly.
EXPECT_EQ(android::aidl::compile_aidl_to_java(options, io_delegate_), 0);
CheckFileContents(kJavaOutputPath, kExpectedJavaOutputOutlining);
- CheckFileContents(options.DependencyFilePath(), kExpectedJavaDepsOutput);
+ CheckFileContents(options.DependencyFile(), kExpectedJavaDepsOutput);
}
TEST_F(EndToEndTest, IPingResponderCpp) {
@@ -172,19 +172,19 @@
"aidl-cpp", "-ddeps.P", "-I.", input_path.c_str(), kGenHeaderDir,
output_file.c_str(), nullptr
};
- auto options = CppOptions::Parse(argc, cmdline);
+ Options options(argc, cmdline, Options::Language::CPP);
// Set up input paths.
io_delegate_.SetFileContents(input_path, kInterfaceDefinition);
AddStubAidls(kImportedParcelables, kImportedInterfaces, kCppParcelableHeader);
// Check that we parse and generate code correctly.
- EXPECT_EQ(android::aidl::compile_aidl_to_cpp(*options, io_delegate_), 0);
+ EXPECT_EQ(android::aidl::compile_aidl_to_cpp(options, io_delegate_), 0);
CheckFileContents(output_file, kExpectedCppOutput);
CheckFileContents(kGenInterfaceHeaderPath, kExpectedIHeaderOutput);
CheckFileContents(kGenClientHeaderPath, kExpectedBpHeaderOutput);
CheckFileContents(kGenServerHeaderPath, kExpectedBnHeaderOutput);
- CheckFileContents(options->DependencyFilePath(), kExpectedCppDepsOutput);
+ CheckFileContents(options.DependencyFile(), kExpectedCppDepsOutput);
}
TEST_F(EndToEndTest, StringConstantsInCpp) {
@@ -197,13 +197,13 @@
"aidl-cpp", input_path.c_str(), kGenHeaderDir,
output_file.c_str(), nullptr
};
- auto options = CppOptions::Parse(argc, cmdline);
+ Options options(argc, cmdline, Options::Language::CPP);
// Set up input paths.
io_delegate_.SetFileContents(input_path, kInterfaceDefinition);
// Check that we parse and generate code correctly.
- EXPECT_EQ(android::aidl::compile_aidl_to_cpp(*options, io_delegate_), 0);
+ EXPECT_EQ(android::aidl::compile_aidl_to_cpp(options, io_delegate_), 0);
CheckFileContents(output_file, kExpectedCppOutput);
CheckFileContents(kGenInterfaceHeaderPath, kExpectedIHeaderOutput);
}
@@ -215,19 +215,15 @@
const string output_file = kJavaOutputPath;
const size_t argc = 4;
const char* cmdline[argc + 1] = {
- "aidl",
- "-b",
- input_path.c_str(),
- output_file.c_str(),
- nullptr,
-};
- auto options = JavaOptions::Parse(argc, cmdline);
+ "aidl", "-b", input_path.c_str(), output_file.c_str(), nullptr,
+ };
+ Options options(argc, cmdline, Options::Language::JAVA);
// Load up our fake file system with data.
io_delegate_.SetFileContents(input_path, kInterfaceDefinition);
// Check that we parse correctly.
- EXPECT_EQ(android::aidl::compile_aidl_to_java(*options, io_delegate_), 0);
+ EXPECT_EQ(android::aidl::compile_aidl_to_java(options, io_delegate_), 0);
CheckFileContents(kJavaOutputPath, kExpectedJavaOutput);
}