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
684d45b2
Commit
684d45b2
authored
Dec 19, 2009
by
kenton@google.com
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Fix build on MinGW/Win32 (including implementing Subprocess using CreateProcess()).
parent
bdbb8630
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
318 additions
and
9 deletions
+318
-9
command_line_interface.cc
src/google/protobuf/compiler/command_line_interface.cc
+9
-0
command_line_interface_unittest.cc
...ogle/protobuf/compiler/command_line_interface_unittest.cc
+19
-0
plugin.cc
src/google/protobuf/compiler/plugin.cc
+10
-0
subprocess.cc
src/google/protobuf/compiler/subprocess.cc
+231
-1
subprocess.h
src/google/protobuf/compiler/subprocess.h
+25
-3
descriptor.cc
src/google/protobuf/descriptor.cc
+21
-4
gzip_stream.cc
src/google/protobuf/io/gzip_stream.cc
+1
-1
repeated_field_unittest.cc
src/google/protobuf/repeated_field_unittest.cc
+2
-0
No files found.
src/google/protobuf/compiler/command_line_interface.cc
View file @
684d45b2
...
...
@@ -529,10 +529,19 @@ CommandLineInterface::InsertionOutputStream::~InsertionOutputStream() {
// If everything was successful, overwrite the original file with the temp
// file.
if
(
!
had_error
)
{
#ifdef _WIN32
// rename() on Windows fails if the file exists.
if
(
!
MoveFileEx
(
temp_filename_
.
c_str
(),
filename_
.
c_str
(),
MOVEFILE_REPLACE_EXISTING
))
{
cerr
<<
filename_
<<
": MoveFileEx: "
<<
Subprocess
::
Win32ErrorMessage
(
GetLastError
())
<<
endl
;
}
#else // _WIN32
if
(
rename
(
temp_filename_
.
c_str
(),
filename_
.
c_str
())
<
0
)
{
cerr
<<
filename_
<<
": rename: "
<<
strerror
(
errno
)
<<
endl
;
had_error
=
true
;
}
#endif // !_WIN32
}
if
(
had_error
)
{
...
...
src/google/protobuf/compiler/command_line_interface_unittest.cc
View file @
684d45b2
...
...
@@ -248,7 +248,11 @@ void CommandLineInterfaceTest::Run(const string& command) {
if
(
!
disallow_plugins_
)
{
cli_
.
AllowPlugins
(
"prefix-"
);
#ifdef _WIN32
args
.
push_back
(
"--plugin=prefix-gen-plug=test_plugin.exe"
);
#else
args
.
push_back
(
"--plugin=prefix-gen-plug=test_plugin"
);
#endif
}
scoped_array
<
const
char
*>
argv
(
new
const
char
*
[
args
.
size
()]);
...
...
@@ -1026,9 +1030,16 @@ TEST_F(CommandLineInterfaceTest, GeneratorPluginCrash) {
ExpectErrorSubstring
(
"Saw message type MockCodeGenerator_Abort."
);
#ifdef _WIN32
// Windows doesn't have signals. It looks like abort()ing causes the process
// to exit with status code 3, but let's not depend on the exact number here.
ExpectErrorSubstring
(
"--plug_out: prefix-gen-plug: Plugin failed with status code"
);
#else
// Don't depend on the exact signal number.
ExpectErrorSubstring
(
"--plug_out: prefix-gen-plug: Plugin killed by signal"
);
#endif
}
TEST_F
(
CommandLineInterfaceTest
,
GeneratorPluginNotFound
)
{
...
...
@@ -1042,11 +1053,19 @@ TEST_F(CommandLineInterfaceTest, GeneratorPluginNotFound) {
"--plugin=prefix-gen-badplug=no_such_file "
"--proto_path=$tmpdir error.proto"
);
#ifdef _WIN32
ExpectErrorSubstring
(
"--badplug_out: prefix-gen-badplug: The system cannot find the file "
"specified."
);
#else
// Error written to stdout by child process after exec() fails.
ExpectErrorSubstring
(
"no_such_file: program not found or is not executable"
);
// Error written by parent process when child fails.
ExpectErrorSubstring
(
"--badplug_out: prefix-gen-badplug: Plugin failed with status code 1."
);
#endif
}
TEST_F
(
CommandLineInterfaceTest
,
GeneratorPluginNotAllowed
)
{
...
...
src/google/protobuf/compiler/plugin.cc
View file @
684d45b2
...
...
@@ -36,6 +36,11 @@
#include <set>
#include <unistd.h>
#ifdef _WIN32
#include <io.h>
#include <fcntl.h>
#endif
#include <google/protobuf/stubs/common.h>
#include <google/protobuf/compiler/plugin.pb.h>
#include <google/protobuf/compiler/code_generator.h>
...
...
@@ -80,6 +85,11 @@ int PluginMain(int argc, char* argv[], const CodeGenerator* generator) {
return
1
;
}
#ifdef _WIN32
_setmode
(
STDIN_FILENO
,
_O_BINARY
);
_setmode
(
STDOUT_FILENO
,
_O_BINARY
);
#endif
CodeGeneratorRequest
request
;
if
(
!
request
.
ParseFromFileDescriptor
(
STDIN_FILENO
))
{
cerr
<<
argv
[
0
]
<<
": protoc sent unparseable request to plugin."
<<
endl
;
...
...
src/google/protobuf/compiler/subprocess.cc
View file @
684d45b2
...
...
@@ -32,9 +32,12 @@
#include <google/protobuf/compiler/subprocess.h>
#i
nclude <algorithm>
#i
fndef _WIN32
#include <errno.h>
#include <sys/wait.h>
#endif
#include <algorithm>
#include <google/protobuf/stubs/common.h>
#include <google/protobuf/message.h>
#include <google/protobuf/stubs/substitute.h>
...
...
@@ -43,6 +46,231 @@ namespace google {
namespace
protobuf
{
namespace
compiler
{
#ifdef _WIN32
static
void
CloseHandleOrDie
(
HANDLE
handle
)
{
if
(
!
CloseHandle
(
handle
))
{
GOOGLE_LOG
(
FATAL
)
<<
"CloseHandle: "
<<
Subprocess
::
Win32ErrorMessage
(
GetLastError
());
}
}
Subprocess
::
Subprocess
()
:
process_start_error_
(
ERROR_SUCCESS
),
child_handle_
(
NULL
),
child_stdin_
(
NULL
),
child_stdout_
(
NULL
)
{}
Subprocess
::~
Subprocess
()
{
if
(
child_stdin_
!=
NULL
)
{
CloseHandleOrDie
(
child_stdin_
);
}
if
(
child_stdout_
!=
NULL
)
{
CloseHandleOrDie
(
child_stdout_
);
}
}
void
Subprocess
::
Start
(
const
string
&
program
,
SearchMode
search_mode
)
{
// Create the pipes.
HANDLE
stdin_pipe_read
;
HANDLE
stdin_pipe_write
;
HANDLE
stdout_pipe_read
;
HANDLE
stdout_pipe_write
;
if
(
!
CreatePipe
(
&
stdin_pipe_read
,
&
stdin_pipe_write
,
NULL
,
0
))
{
GOOGLE_LOG
(
FATAL
)
<<
"CreatePipe: "
<<
Win32ErrorMessage
(
GetLastError
());
}
if
(
!
CreatePipe
(
&
stdout_pipe_read
,
&
stdout_pipe_write
,
NULL
,
0
))
{
GOOGLE_LOG
(
FATAL
)
<<
"CreatePipe: "
<<
Win32ErrorMessage
(
GetLastError
());
}
// Make child side of the pipes inheritable.
if
(
!
SetHandleInformation
(
stdin_pipe_read
,
HANDLE_FLAG_INHERIT
,
HANDLE_FLAG_INHERIT
))
{
GOOGLE_LOG
(
FATAL
)
<<
"SetHandleInformation: "
<<
Win32ErrorMessage
(
GetLastError
());
}
if
(
!
SetHandleInformation
(
stdout_pipe_write
,
HANDLE_FLAG_INHERIT
,
HANDLE_FLAG_INHERIT
))
{
GOOGLE_LOG
(
FATAL
)
<<
"SetHandleInformation: "
<<
Win32ErrorMessage
(
GetLastError
());
}
// Setup STARTUPINFO to redirect handles.
STARTUPINFO
startup_info
;
ZeroMemory
(
&
startup_info
,
sizeof
(
startup_info
));
startup_info
.
cb
=
sizeof
(
startup_info
);
startup_info
.
dwFlags
=
STARTF_USESTDHANDLES
;
startup_info
.
hStdInput
=
stdin_pipe_read
;
startup_info
.
hStdOutput
=
stdout_pipe_write
;
startup_info
.
hStdError
=
GetStdHandle
(
STD_ERROR_HANDLE
);
if
(
startup_info
.
hStdError
==
INVALID_HANDLE_VALUE
)
{
GOOGLE_LOG
(
FATAL
)
<<
"GetStdHandle: "
<<
Win32ErrorMessage
(
GetLastError
());
}
// CreateProcess() mutates its second parameter. WTF?
char
*
name_copy
=
strdup
(
program
.
c_str
());
// Create the process.
PROCESS_INFORMATION
process_info
;
if
(
CreateProcess
((
search_mode
==
SEARCH_PATH
)
?
NULL
:
program
.
c_str
(),
(
search_mode
==
SEARCH_PATH
)
?
name_copy
:
NULL
,
NULL
,
// process security attributes
NULL
,
// thread security attributes
TRUE
,
// inherit handles?
0
,
// obscure creation flags
NULL
,
// environment (inherit from parent)
NULL
,
// current directory (inherit from parent)
&
startup_info
,
&
process_info
))
{
child_handle_
=
process_info
.
hProcess
;
CloseHandleOrDie
(
process_info
.
hThread
);
child_stdin_
=
stdin_pipe_write
;
child_stdout_
=
stdout_pipe_read
;
}
else
{
process_start_error_
=
GetLastError
();
CloseHandleOrDie
(
stdin_pipe_write
);
CloseHandleOrDie
(
stdout_pipe_read
);
}
CloseHandleOrDie
(
stdin_pipe_read
);
CloseHandleOrDie
(
stdout_pipe_write
);
free
(
name_copy
);
}
bool
Subprocess
::
Communicate
(
const
Message
&
input
,
Message
*
output
,
string
*
error
)
{
if
(
process_start_error_
!=
ERROR_SUCCESS
)
{
*
error
=
Win32ErrorMessage
(
process_start_error_
);
return
false
;
}
GOOGLE_CHECK
(
child_handle_
!=
NULL
)
<<
"Must call Start() first."
;
string
input_data
=
input
.
SerializeAsString
();
string
output_data
;
int
input_pos
=
0
;
while
(
child_stdout_
!=
NULL
)
{
HANDLE
handles
[
2
];
int
handle_count
=
0
;
if
(
child_stdin_
!=
NULL
)
{
handles
[
handle_count
++
]
=
child_stdin_
;
}
if
(
child_stdout_
!=
NULL
)
{
handles
[
handle_count
++
]
=
child_stdout_
;
}
DWORD
wait_result
=
WaitForMultipleObjects
(
handle_count
,
handles
,
FALSE
,
INFINITE
);
HANDLE
signaled_handle
;
if
(
wait_result
>=
WAIT_OBJECT_0
&&
wait_result
<
WAIT_OBJECT_0
+
handle_count
)
{
signaled_handle
=
handles
[
wait_result
-
WAIT_OBJECT_0
];
}
else
if
(
wait_result
==
WAIT_FAILED
)
{
GOOGLE_LOG
(
FATAL
)
<<
"WaitForMultipleObjects: "
<<
Win32ErrorMessage
(
GetLastError
());
}
else
{
GOOGLE_LOG
(
FATAL
)
<<
"WaitForMultipleObjects: Unexpected return code: "
<<
wait_result
;
}
if
(
signaled_handle
==
child_stdin_
)
{
DWORD
n
;
if
(
!
WriteFile
(
child_stdin_
,
input_data
.
data
()
+
input_pos
,
input_data
.
size
()
-
input_pos
,
&
n
,
NULL
))
{
// Child closed pipe. Presumably it will report an error later.
// Pretend we're done for now.
input_pos
=
input_data
.
size
();
}
else
{
input_pos
+=
n
;
}
if
(
input_pos
==
input_data
.
size
())
{
// We're done writing. Close.
CloseHandleOrDie
(
child_stdin_
);
child_stdin_
=
NULL
;
}
}
else
if
(
signaled_handle
==
child_stdout_
)
{
char
buffer
[
4096
];
DWORD
n
;
if
(
!
ReadFile
(
child_stdout_
,
buffer
,
sizeof
(
buffer
),
&
n
,
NULL
))
{
// We're done reading. Close.
CloseHandleOrDie
(
child_stdout_
);
child_stdout_
=
NULL
;
}
else
{
output_data
.
append
(
buffer
,
n
);
}
}
}
if
(
child_stdin_
!=
NULL
)
{
// Child did not finish reading input before it closed the output.
// Presumably it exited with an error.
CloseHandleOrDie
(
child_stdin_
);
child_stdin_
=
NULL
;
}
DWORD
wait_result
=
WaitForSingleObject
(
child_handle_
,
INFINITE
);
if
(
wait_result
==
WAIT_FAILED
)
{
GOOGLE_LOG
(
FATAL
)
<<
"WaitForSingleObject: "
<<
Win32ErrorMessage
(
GetLastError
());
}
else
if
(
wait_result
!=
WAIT_OBJECT_0
)
{
GOOGLE_LOG
(
FATAL
)
<<
"WaitForSingleObject: Unexpected return code: "
<<
wait_result
;
}
DWORD
exit_code
;
if
(
!
GetExitCodeProcess
(
child_handle_
,
&
exit_code
))
{
GOOGLE_LOG
(
FATAL
)
<<
"GetExitCodeProcess: "
<<
Win32ErrorMessage
(
GetLastError
());
}
CloseHandleOrDie
(
child_handle_
);
child_handle_
=
NULL
;
if
(
exit_code
!=
0
)
{
*
error
=
strings
::
Substitute
(
"Plugin failed with status code $0."
,
exit_code
);
return
false
;
}
if
(
!
output
->
ParseFromString
(
output_data
))
{
*
error
=
"Plugin output is unparseable: "
+
CEscape
(
output_data
);
return
false
;
}
return
true
;
}
string
Subprocess
::
Win32ErrorMessage
(
DWORD
error_code
)
{
char
*
message
;
// WTF?
FormatMessage
(
FORMAT_MESSAGE_ALLOCATE_BUFFER
|
FORMAT_MESSAGE_FROM_SYSTEM
|
FORMAT_MESSAGE_IGNORE_INSERTS
,
NULL
,
error_code
,
0
,
(
LPTSTR
)
&
message
,
// NOT A BUG!
0
,
NULL
);
string
result
=
message
;
LocalFree
(
message
);
return
result
;
}
// ===================================================================
#else // _WIN32
Subprocess
::
Subprocess
()
:
child_pid_
(
-
1
),
child_stdin_
(
-
1
),
child_stdout_
(
-
1
)
{}
...
...
@@ -222,6 +450,8 @@ bool Subprocess::Communicate(const Message& input, Message* output,
return
true
;
}
#endif // !_WIN32
}
// namespace compiler
}
// namespace protobuf
}
// namespace google
src/google/protobuf/compiler/subprocess.h
View file @
684d45b2
...
...
@@ -33,12 +33,16 @@
#ifndef GOOGLE_PROTOBUF_COMPILER_SUBPROCESS_H__
#define GOOGLE_PROTOBUF_COMPILER_SUBPROCESS_H__
#include <vector>
#include <string>
#ifdef _WIN32
#define WIN32_LEAN_AND_MEAN // right...
#include <windows.h>
#else // _WIN32
#include <sys/types.h>
#include <unistd.h>
#
include <google/protobuf/stubs/common.h>
#
endif // !_WIN32
#include <string>
#include <google/protobuf/stubs/common.h>
namespace
google
{
namespace
protobuf
{
...
...
@@ -69,13 +73,31 @@ class Subprocess {
// *error to a description of the problem.
bool
Communicate
(
const
Message
&
input
,
Message
*
output
,
string
*
error
);
#ifdef _WIN32
// Given an error code, returns a human-readable error message. This is
// defined here so that CommandLineInterface can share it.
static
string
Subprocess
::
Win32ErrorMessage
(
DWORD
error_code
);
#endif
private
:
#ifdef _WIN32
DWORD
process_start_error_
;
HANDLE
child_handle_
;
// The file handles for our end of the child's pipes. We close each and
// set it to NULL when no longer needed.
HANDLE
child_stdin_
;
HANDLE
child_stdout_
;
#else // _WIN32
pid_t
child_pid_
;
// The file descriptors for our end of the child's pipes. We close each and
// set it to -1 when no longer needed.
int
child_stdin_
;
int
child_stdout_
;
#endif // !_WIN32
};
}
// namespace compiler
...
...
src/google/protobuf/descriptor.cc
View file @
684d45b2
...
...
@@ -37,6 +37,7 @@
#include <set>
#include <vector>
#include <algorithm>
#include <limits>
#include <google/protobuf/descriptor.h>
#include <google/protobuf/descriptor_database.h>
...
...
@@ -3000,12 +3001,28 @@ void DescriptorBuilder::BuildFieldOrExtension(const FieldDescriptorProto& proto,
strtou64
(
proto
.
default_value
().
c_str
(),
&
end_pos
,
0
);
break
;
case
FieldDescriptor
:
:
CPPTYPE_FLOAT
:
result
->
default_value_float_
=
NoLocaleStrtod
(
proto
.
default_value
().
c_str
(),
&
end_pos
);
if
(
proto
.
default_value
()
==
"inf"
)
{
result
->
default_value_float_
=
numeric_limits
<
float
>::
infinity
();
}
else
if
(
proto
.
default_value
()
==
"-inf"
)
{
result
->
default_value_float_
=
-
numeric_limits
<
float
>::
infinity
();
}
else
if
(
proto
.
default_value
()
==
"nan"
)
{
result
->
default_value_float_
=
numeric_limits
<
float
>::
quiet_NaN
();
}
else
{
result
->
default_value_float_
=
NoLocaleStrtod
(
proto
.
default_value
().
c_str
(),
&
end_pos
);
}
break
;
case
FieldDescriptor
:
:
CPPTYPE_DOUBLE
:
result
->
default_value_double_
=
NoLocaleStrtod
(
proto
.
default_value
().
c_str
(),
&
end_pos
);
if
(
proto
.
default_value
()
==
"inf"
)
{
result
->
default_value_double_
=
numeric_limits
<
double
>::
infinity
();
}
else
if
(
proto
.
default_value
()
==
"-inf"
)
{
result
->
default_value_double_
=
-
numeric_limits
<
double
>::
infinity
();
}
else
if
(
proto
.
default_value
()
==
"nan"
)
{
result
->
default_value_double_
=
numeric_limits
<
double
>::
quiet_NaN
();
}
else
{
result
->
default_value_double_
=
NoLocaleStrtod
(
proto
.
default_value
().
c_str
(),
&
end_pos
);
}
break
;
case
FieldDescriptor
:
:
CPPTYPE_BOOL
:
if
(
proto
.
default_value
()
==
"true"
)
{
...
...
src/google/protobuf/io/gzip_stream.cc
View file @
684d45b2
...
...
@@ -315,6 +315,6 @@ bool GzipOutputStream::Close() {
}
// namespace io
}
// namespace protobuf
}
// namespace google
#endif // HAVE_ZLIB
}
// namespace google
src/google/protobuf/repeated_field_unittest.cc
View file @
684d45b2
...
...
@@ -261,7 +261,9 @@ TEST(RepeatedField, Truncate) {
// Truncations that don't change the size are allowed, but growing is not
// allowed.
field
.
Truncate
(
field
.
size
());
#ifdef GTEST_HAS_DEATH_TEST
EXPECT_DEBUG_DEATH
(
field
.
Truncate
(
field
.
size
()
+
1
),
"new_size"
);
#endif
}
...
...
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