Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in / Register
Toggle navigation
P
protobuf
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Packages
Packages
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
submodule
protobuf
Commits
a5f7bb8e
Commit
a5f7bb8e
authored
Mar 08, 2015
by
Paul Yang
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #193 from TeBoring/sb
Implement a feature to generate a dependency file
parents
88eda4d7
eb2ce029
Show whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
215 additions
and
2 deletions
+215
-2
command_line_interface.cc
src/google/protobuf/compiler/command_line_interface.cc
+112
-2
command_line_interface.h
src/google/protobuf/compiler/command_line_interface.h
+12
-0
command_line_interface_unittest.cc
...ogle/protobuf/compiler/command_line_interface_unittest.cc
+84
-0
file.cc
src/google/protobuf/testing/file.cc
+4
-0
file.h
src/google/protobuf/testing/file.h
+3
-0
No files found.
src/google/protobuf/compiler/command_line_interface.cc
View file @
a5f7bb8e
...
@@ -48,7 +48,6 @@
...
@@ -48,7 +48,6 @@
#include <iostream>
#include <iostream>
#include <ctype.h>
#include <ctype.h>
#include <google/protobuf/stubs/hash.h>
#include <memory>
#include <memory>
#ifndef _SHARED_PTR_H
#ifndef _SHARED_PTR_H
#include <google/protobuf/stubs/shared_ptr.h>
#include <google/protobuf/stubs/shared_ptr.h>
...
@@ -255,6 +254,9 @@ class CommandLineInterface::GeneratorContextImpl : public GeneratorContext {
...
@@ -255,6 +254,9 @@ class CommandLineInterface::GeneratorContextImpl : public GeneratorContext {
// format, unless one has already been written.
// format, unless one has already been written.
void
AddJarManifest
();
void
AddJarManifest
();
// Get name of all output files.
void
GetOutputFilenames
(
vector
<
string
>*
output_filenames
);
// implements GeneratorContext --------------------------------------
// implements GeneratorContext --------------------------------------
io
::
ZeroCopyOutputStream
*
Open
(
const
string
&
filename
);
io
::
ZeroCopyOutputStream
*
Open
(
const
string
&
filename
);
io
::
ZeroCopyOutputStream
*
OpenForAppend
(
const
string
&
filename
);
io
::
ZeroCopyOutputStream
*
OpenForAppend
(
const
string
&
filename
);
...
@@ -442,6 +444,14 @@ void CommandLineInterface::GeneratorContextImpl::AddJarManifest() {
...
@@ -442,6 +444,14 @@ void CommandLineInterface::GeneratorContextImpl::AddJarManifest() {
}
}
}
}
void
CommandLineInterface
::
GeneratorContextImpl
::
GetOutputFilenames
(
vector
<
string
>*
output_filenames
)
{
for
(
map
<
string
,
string
*>::
iterator
iter
=
files_
.
begin
();
iter
!=
files_
.
end
();
++
iter
)
{
output_filenames
->
push_back
(
iter
->
first
);
}
}
io
::
ZeroCopyOutputStream
*
CommandLineInterface
::
GeneratorContextImpl
::
Open
(
io
::
ZeroCopyOutputStream
*
CommandLineInterface
::
GeneratorContextImpl
::
Open
(
const
string
&
filename
)
{
const
string
&
filename
)
{
return
new
MemoryOutputStream
(
this
,
filename
,
false
);
return
new
MemoryOutputStream
(
this
,
filename
,
false
);
...
@@ -673,7 +683,6 @@ int CommandLineInterface::Run(int argc, const char* const argv[]) {
...
@@ -673,7 +683,6 @@ int CommandLineInterface::Run(int argc, const char* const argv[]) {
// We construct a separate GeneratorContext for each output location. Note
// We construct a separate GeneratorContext for each output location. Note
// that two code generators may output to the same location, in which case
// that two code generators may output to the same location, in which case
// they should share a single GeneratorContext so that OpenForInsert() works.
// they should share a single GeneratorContext so that OpenForInsert() works.
typedef
hash_map
<
string
,
GeneratorContextImpl
*>
GeneratorContextMap
;
GeneratorContextMap
output_directories
;
GeneratorContextMap
output_directories
;
// Generate output.
// Generate output.
...
@@ -720,6 +729,13 @@ int CommandLineInterface::Run(int argc, const char* const argv[]) {
...
@@ -720,6 +729,13 @@ int CommandLineInterface::Run(int argc, const char* const argv[]) {
}
}
}
}
if
(
!
dependency_out_name_
.
empty
())
{
if
(
!
GenerateDependencyManifestFile
(
parsed_files
,
output_directories
,
&
source_tree
))
{
return
1
;
}
}
STLDeleteValues
(
&
output_directories
);
STLDeleteValues
(
&
output_directories
);
if
(
!
descriptor_set_name_
.
empty
())
{
if
(
!
descriptor_set_name_
.
empty
())
{
...
@@ -778,6 +794,7 @@ void CommandLineInterface::Clear() {
...
@@ -778,6 +794,7 @@ void CommandLineInterface::Clear() {
output_directives_
.
clear
();
output_directives_
.
clear
();
codec_type_
.
clear
();
codec_type_
.
clear
();
descriptor_set_name_
.
clear
();
descriptor_set_name_
.
clear
();
dependency_out_name_
.
clear
();
mode_
=
MODE_COMPILE
;
mode_
=
MODE_COMPILE
;
print_mode_
=
PRINT_NONE
;
print_mode_
=
PRINT_NONE
;
...
@@ -880,6 +897,15 @@ CommandLineInterface::ParseArguments(int argc, const char* const argv[]) {
...
@@ -880,6 +897,15 @@ CommandLineInterface::ParseArguments(int argc, const char* const argv[]) {
std
::
cerr
<<
"Missing output directives."
<<
std
::
endl
;
std
::
cerr
<<
"Missing output directives."
<<
std
::
endl
;
return
PARSE_ARGUMENT_FAIL
;
return
PARSE_ARGUMENT_FAIL
;
}
}
if
(
mode_
!=
MODE_COMPILE
&&
!
dependency_out_name_
.
empty
())
{
cerr
<<
"Can only use --dependency_out=FILE when generating code."
<<
endl
;
return
PARSE_ARGUMENT_FAIL
;
}
if
(
!
dependency_out_name_
.
empty
()
&&
input_files_
.
size
()
>
1
)
{
cerr
<<
"Can only process one input file when using --dependency_out=FILE."
<<
endl
;
return
PARSE_ARGUMENT_FAIL
;
}
if
(
imports_in_descriptor_set_
&&
descriptor_set_name_
.
empty
())
{
if
(
imports_in_descriptor_set_
&&
descriptor_set_name_
.
empty
())
{
std
::
cerr
<<
"--include_imports only makes sense when combined with "
std
::
cerr
<<
"--include_imports only makes sense when combined with "
"--descriptor_set_out."
<<
std
::
endl
;
"--descriptor_set_out."
<<
std
::
endl
;
...
@@ -1026,6 +1052,17 @@ CommandLineInterface::InterpretArgument(const string& name,
...
@@ -1026,6 +1052,17 @@ CommandLineInterface::InterpretArgument(const string& name,
}
}
descriptor_set_name_
=
value
;
descriptor_set_name_
=
value
;
}
else
if
(
name
==
"--dependency_out"
)
{
if
(
!
dependency_out_name_
.
empty
())
{
cerr
<<
name
<<
" may only be passed once."
<<
endl
;
return
PARSE_ARGUMENT_FAIL
;
}
if
(
value
.
empty
())
{
cerr
<<
name
<<
" requires a non-empty value."
<<
endl
;
return
PARSE_ARGUMENT_FAIL
;
}
dependency_out_name_
=
value
;
}
else
if
(
name
==
"--include_imports"
)
{
}
else
if
(
name
==
"--include_imports"
)
{
if
(
imports_in_descriptor_set_
)
{
if
(
imports_in_descriptor_set_
)
{
std
::
cerr
<<
name
<<
" may only be passed once."
<<
std
::
endl
;
std
::
cerr
<<
name
<<
" may only be passed once."
<<
std
::
endl
;
...
@@ -1225,6 +1262,9 @@ void CommandLineInterface::PrintHelpText() {
...
@@ -1225,6 +1262,9 @@ void CommandLineInterface::PrintHelpText() {
" include information about the original
\n
"
" include information about the original
\n
"
" location of each decl in the source file as
\n
"
" location of each decl in the source file as
\n
"
" well as surrounding comments.
\n
"
" well as surrounding comments.
\n
"
" --dependency_out=FILE Write a dependency output file in the format
\n
"
" expected by make. This writes the transitive
\n
"
" set of input file paths to FILE
\n
"
" --error_format=FORMAT Set the format in which to print errors.
\n
"
" --error_format=FORMAT Set the format in which to print errors.
\n
"
" FORMAT may be 'gcc' (the default) or 'msvs'
\n
"
" FORMAT may be 'gcc' (the default) or 'msvs'
\n
"
" (Microsoft Visual Studio format).
\n
"
" (Microsoft Visual Studio format).
\n
"
...
@@ -1301,6 +1341,76 @@ bool CommandLineInterface::GenerateOutput(
...
@@ -1301,6 +1341,76 @@ bool CommandLineInterface::GenerateOutput(
return
true
;
return
true
;
}
}
bool
CommandLineInterface
::
GenerateDependencyManifestFile
(
const
vector
<
const
FileDescriptor
*>&
parsed_files
,
const
GeneratorContextMap
&
output_directories
,
DiskSourceTree
*
source_tree
)
{
FileDescriptorSet
file_set
;
set
<
const
FileDescriptor
*>
already_seen
;
for
(
int
i
=
0
;
i
<
parsed_files
.
size
();
i
++
)
{
GetTransitiveDependencies
(
parsed_files
[
i
],
false
,
&
already_seen
,
file_set
.
mutable_file
());
}
vector
<
string
>
output_filenames
;
for
(
GeneratorContextMap
::
const_iterator
iter
=
output_directories
.
begin
();
iter
!=
output_directories
.
end
();
++
iter
)
{
const
string
&
location
=
iter
->
first
;
GeneratorContextImpl
*
directory
=
iter
->
second
;
vector
<
string
>
relative_output_filenames
;
directory
->
GetOutputFilenames
(
&
relative_output_filenames
);
for
(
int
i
=
0
;
i
<
relative_output_filenames
.
size
();
i
++
)
{
string
output_filename
=
location
+
relative_output_filenames
[
i
];
if
(
output_filename
.
compare
(
0
,
2
,
"./"
)
==
0
)
{
output_filename
=
output_filename
.
substr
(
2
);
}
output_filenames
.
push_back
(
output_filename
);
}
}
int
fd
;
do
{
fd
=
open
(
dependency_out_name_
.
c_str
(),
O_WRONLY
|
O_CREAT
|
O_TRUNC
|
O_BINARY
,
0666
);
}
while
(
fd
<
0
&&
errno
==
EINTR
);
if
(
fd
<
0
)
{
perror
(
dependency_out_name_
.
c_str
());
return
false
;
}
io
::
FileOutputStream
out
(
fd
);
io
::
Printer
printer
(
&
out
,
'$'
);
for
(
int
i
=
0
;
i
<
output_filenames
.
size
();
i
++
)
{
printer
.
Print
(
output_filenames
[
i
].
c_str
());
if
(
i
==
output_filenames
.
size
()
-
1
)
{
printer
.
Print
(
":"
);
}
else
{
printer
.
Print
(
"
\\\n
"
);
}
}
for
(
int
i
=
0
;
i
<
file_set
.
file_size
();
i
++
)
{
const
FileDescriptorProto
&
file
=
file_set
.
file
(
i
);
const
string
&
virtual_file
=
file
.
name
();
string
disk_file
;
if
(
source_tree
&&
source_tree
->
VirtualFileToDiskFile
(
virtual_file
,
&
disk_file
))
{
printer
.
Print
(
" $disk_file$"
,
"disk_file"
,
disk_file
);
if
(
i
<
file_set
.
file_size
()
-
1
)
printer
.
Print
(
"
\\\n
"
);
}
else
{
cerr
<<
"Unable to identify path for file "
<<
virtual_file
<<
endl
;
return
false
;
}
}
return
true
;
}
bool
CommandLineInterface
::
GeneratePluginOutput
(
bool
CommandLineInterface
::
GeneratePluginOutput
(
const
vector
<
const
FileDescriptor
*>&
parsed_files
,
const
vector
<
const
FileDescriptor
*>&
parsed_files
,
const
string
&
plugin_name
,
const
string
&
plugin_name
,
...
...
src/google/protobuf/compiler/command_line_interface.h
View file @
a5f7bb8e
...
@@ -39,6 +39,7 @@
...
@@ -39,6 +39,7 @@
#define GOOGLE_PROTOBUF_COMPILER_COMMAND_LINE_INTERFACE_H__
#define GOOGLE_PROTOBUF_COMPILER_COMMAND_LINE_INTERFACE_H__
#include <google/protobuf/stubs/common.h>
#include <google/protobuf/stubs/common.h>
#include <google/protobuf/stubs/hash.h>
#include <string>
#include <string>
#include <vector>
#include <vector>
#include <map>
#include <map>
...
@@ -190,6 +191,7 @@ class LIBPROTOC_EXPORT CommandLineInterface {
...
@@ -190,6 +191,7 @@ class LIBPROTOC_EXPORT CommandLineInterface {
class
ErrorPrinter
;
class
ErrorPrinter
;
class
GeneratorContextImpl
;
class
GeneratorContextImpl
;
class
MemoryOutputStream
;
class
MemoryOutputStream
;
typedef
hash_map
<
string
,
GeneratorContextImpl
*>
GeneratorContextMap
;
// Clear state from previous Run().
// Clear state from previous Run().
void
Clear
();
void
Clear
();
...
@@ -247,6 +249,12 @@ class LIBPROTOC_EXPORT CommandLineInterface {
...
@@ -247,6 +249,12 @@ class LIBPROTOC_EXPORT CommandLineInterface {
// Implements the --descriptor_set_out option.
// Implements the --descriptor_set_out option.
bool
WriteDescriptorSet
(
const
vector
<
const
FileDescriptor
*>
parsed_files
);
bool
WriteDescriptorSet
(
const
vector
<
const
FileDescriptor
*>
parsed_files
);
// Implements the --dependency_out option
bool
GenerateDependencyManifestFile
(
const
vector
<
const
FileDescriptor
*>&
parsed_files
,
const
GeneratorContextMap
&
output_directories
,
DiskSourceTree
*
source_tree
);
// Get all transitive dependencies of the given file (including the file
// Get all transitive dependencies of the given file (including the file
// itself), adding them to the given list of FileDescriptorProtos. The
// itself), adding them to the given list of FileDescriptorProtos. The
// protos will be ordered such that every file is listed before any file that
// protos will be ordered such that every file is listed before any file that
...
@@ -353,6 +361,10 @@ class LIBPROTOC_EXPORT CommandLineInterface {
...
@@ -353,6 +361,10 @@ class LIBPROTOC_EXPORT CommandLineInterface {
// FileDescriptorSet should be written. Otherwise, empty.
// FileDescriptorSet should be written. Otherwise, empty.
string
descriptor_set_name_
;
string
descriptor_set_name_
;
// If --dependency_out was given, this is the path to the file where the
// dependency file will be written. Otherwise, empty.
string
dependency_out_name_
;
// True if --include_imports was given, meaning that we should
// True if --include_imports was given, meaning that we should
// write all transitive dependencies to the DescriptorSet. Otherwise, only
// write all transitive dependencies to the DescriptorSet. Otherwise, only
// the .proto files listed on the command-line are added.
// the .proto files listed on the command-line are added.
...
...
src/google/protobuf/compiler/command_line_interface_unittest.cc
View file @
a5f7bb8e
...
@@ -115,6 +115,11 @@ class CommandLineInterfaceTest : public testing::Test {
...
@@ -115,6 +115,11 @@ class CommandLineInterfaceTest : public testing::Test {
// Create a subdirectory within temp_directory_.
// Create a subdirectory within temp_directory_.
void
CreateTempDir
(
const
string
&
name
);
void
CreateTempDir
(
const
string
&
name
);
// Change working directory to temp directory.
void
SwitchToTempDirectory
()
{
File
::
ChangeWorkingDirectory
(
temp_directory_
);
}
void
SetInputsAreProtoPathRelative
(
bool
enable
)
{
void
SetInputsAreProtoPathRelative
(
bool
enable
)
{
cli_
.
SetInputsAreProtoPathRelative
(
enable
);
cli_
.
SetInputsAreProtoPathRelative
(
enable
);
}
}
...
@@ -179,6 +184,9 @@ class CommandLineInterfaceTest : public testing::Test {
...
@@ -179,6 +184,9 @@ class CommandLineInterfaceTest : public testing::Test {
void
ReadDescriptorSet
(
const
string
&
filename
,
void
ReadDescriptorSet
(
const
string
&
filename
,
FileDescriptorSet
*
descriptor_set
);
FileDescriptorSet
*
descriptor_set
);
void
ExpectFileContent
(
const
string
&
filename
,
const
string
&
content
);
private
:
private
:
// The object we are testing.
// The object we are testing.
CommandLineInterface
cli_
;
CommandLineInterface
cli_
;
...
@@ -459,6 +467,17 @@ void CommandLineInterfaceTest::ExpectCapturedStdout(
...
@@ -459,6 +467,17 @@ void CommandLineInterfaceTest::ExpectCapturedStdout(
EXPECT_EQ
(
expected_text
,
captured_stdout_
);
EXPECT_EQ
(
expected_text
,
captured_stdout_
);
}
}
void
CommandLineInterfaceTest
::
ExpectFileContent
(
const
string
&
filename
,
const
string
&
content
)
{
string
path
=
temp_directory_
+
"/"
+
filename
;
string
file_contents
;
GOOGLE_CHECK_OK
(
File
::
GetContents
(
path
,
&
file_contents
,
true
));
EXPECT_EQ
(
StringReplace
(
content
,
"$tmpdir"
,
temp_directory_
,
true
),
file_contents
);
}
// ===================================================================
// ===================================================================
TEST_F
(
CommandLineInterfaceTest
,
BasicOutput
)
{
TEST_F
(
CommandLineInterfaceTest
,
BasicOutput
)
{
...
@@ -943,6 +962,71 @@ TEST_F(CommandLineInterfaceTest, WriteTransitiveDescriptorSetWithSourceInfo) {
...
@@ -943,6 +962,71 @@ TEST_F(CommandLineInterfaceTest, WriteTransitiveDescriptorSetWithSourceInfo) {
EXPECT_TRUE
(
descriptor_set
.
file
(
1
).
has_source_code_info
());
EXPECT_TRUE
(
descriptor_set
.
file
(
1
).
has_source_code_info
());
}
}
TEST_F
(
CommandLineInterfaceTest
,
WriteDependencyManifestFileGivenTwoInputs
)
{
CreateTempFile
(
"foo.proto"
,
"syntax =
\"
proto2
\"
;
\n
"
"message Foo {}
\n
"
);
CreateTempFile
(
"bar.proto"
,
"syntax =
\"
proto2
\"
;
\n
"
"import
\"
foo.proto
\"
;
\n
"
"message Bar {
\n
"
" optional Foo foo = 1;
\n
"
"}
\n
"
);
Run
(
"protocol_compiler --dependency_out=$tmpdir/manifest "
"--test_out=$tmpdir --proto_path=$tmpdir bar.proto foo.proto"
);
ExpectErrorText
(
"Can only process one input file when using --dependency_out=FILE.
\n
"
);
}
TEST_F
(
CommandLineInterfaceTest
,
WriteDependencyManifestFile
)
{
CreateTempFile
(
"foo.proto"
,
"syntax =
\"
proto2
\"
;
\n
"
"message Foo {}
\n
"
);
CreateTempFile
(
"bar.proto"
,
"syntax =
\"
proto2
\"
;
\n
"
"import
\"
foo.proto
\"
;
\n
"
"message Bar {
\n
"
" optional Foo foo = 1;
\n
"
"}
\n
"
);
string
current_working_directory
=
get_current_dir_name
();
SwitchToTempDirectory
();
Run
(
"protocol_compiler --dependency_out=manifest --test_out=. "
"bar.proto"
);
ExpectNoErrors
();
ExpectFileContent
(
"manifest"
,
"bar.proto.MockCodeGenerator.test_generator: "
"foo.proto
\\\n
bar.proto"
);
File
::
ChangeWorkingDirectory
(
current_working_directory
);
}
TEST_F
(
CommandLineInterfaceTest
,
WriteDependencyManifestFileForAbsolutePath
)
{
CreateTempFile
(
"foo.proto"
,
"syntax =
\"
proto2
\"
;
\n
"
"message Foo {}
\n
"
);
CreateTempFile
(
"bar.proto"
,
"syntax =
\"
proto2
\"
;
\n
"
"import
\"
foo.proto
\"
;
\n
"
"message Bar {
\n
"
" optional Foo foo = 1;
\n
"
"}
\n
"
);
Run
(
"protocol_compiler --dependency_out=$tmpdir/manifest "
"--test_out=$tmpdir --proto_path=$tmpdir bar.proto"
);
ExpectNoErrors
();
ExpectFileContent
(
"manifest"
,
"$tmpdir/bar.proto.MockCodeGenerator.test_generator: "
"$tmpdir/foo.proto
\\\n
$tmpdir/bar.proto"
);
}
// -------------------------------------------------------------------
// -------------------------------------------------------------------
TEST_F
(
CommandLineInterfaceTest
,
ParseErrors
)
{
TEST_F
(
CommandLineInterfaceTest
,
ParseErrors
)
{
...
...
src/google/protobuf/testing/file.cc
View file @
a5f7bb8e
...
@@ -192,5 +192,9 @@ void File::DeleteRecursively(const string& name,
...
@@ -192,5 +192,9 @@ void File::DeleteRecursively(const string& name,
#endif
#endif
}
}
bool
File
::
ChangeWorkingDirectory
(
const
string
&
new_working_directory
)
{
return
chdir
(
new_working_directory
.
c_str
())
==
0
;
}
}
// namespace protobuf
}
// namespace protobuf
}
// namespace google
}
// namespace google
src/google/protobuf/testing/file.h
View file @
a5f7bb8e
...
@@ -77,6 +77,9 @@ class File {
...
@@ -77,6 +77,9 @@ class File {
static
void
DeleteRecursively
(
const
string
&
name
,
static
void
DeleteRecursively
(
const
string
&
name
,
void
*
dummy1
,
void
*
dummy2
);
void
*
dummy1
,
void
*
dummy2
);
// Change working directory to given directory.
static
bool
ChangeWorkingDirectory
(
const
string
&
new_working_directory
);
static
bool
GetContents
(
static
bool
GetContents
(
const
string
&
name
,
string
*
output
,
bool
/*is_default*/
)
{
const
string
&
name
,
string
*
output
,
bool
/*is_default*/
)
{
return
ReadFileToString
(
name
,
output
);
return
ReadFileToString
(
name
,
output
);
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment