use generated makefile part; port all other makefiles; remove files that were not compiled, and cannot be compiled

This commit is contained in:
Laurent Perron
2016-07-19 13:14:43 -07:00
parent bf10a52a06
commit 476c490176
10 changed files with 1108 additions and 2431 deletions

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -59,7 +59,7 @@ $(GEN_DIR)/ortools/algorithms/pywrapknapsack_solver.py: \
$(GEN_DIR)/ortools/algorithms/knapsack_solver_python_wrap.cc: $(GEN_DIR)/ortools/algorithms/pywrapknapsack_solver.py
$(OBJ_DIR)/swig/knapsack_solver_python_wrap.$O: $(GEN_DIR)/ortools/algorithms/knapsack_solver_python_wrap.cc
$(OBJ_DIR)/swig/knapsack_solver_python_wrap.$O: $(GEN_DIR)/ortools/algorithms/knapsack_solver_python_wrap.cc $(ALGORITHMS_DEPS)
$(CCC) $(CFLAGS) $(PYTHON_INC) -c $(GEN_DIR)$Sortools$Salgorithms$Sknapsack_solver_python_wrap.cc $(OBJ_OUT)$(OBJ_DIR)$Sswig$Sknapsack_solver_python_wrap.$O
$(LIB_DIR)/_pywrapknapsack_solver.$(SWIG_LIB_SUFFIX): $(OBJ_DIR)/swig/knapsack_solver_python_wrap.$O $(OR_TOOLS_LIBS)
@@ -148,7 +148,7 @@ $(GEN_DIR)/ortools/constraint_solver/pywrapcp.py: \
$(GEN_DIR)/ortools/constraint_solver/constraint_solver_python_wrap.cc: $(GEN_DIR)/ortools/constraint_solver/pywrapcp.py
$(OBJ_DIR)/swig/constraint_solver_python_wrap.$O: $(GEN_DIR)/ortools/constraint_solver/constraint_solver_python_wrap.cc $(ROUTING_DEPS)
$(OBJ_DIR)/swig/constraint_solver_python_wrap.$O: $(GEN_DIR)/ortools/constraint_solver/constraint_solver_python_wrap.cc $(CP_DEPS)
$(CCC) $(CFLAGS) $(PYTHON_INC) -c $(GEN_DIR)$Sortools$Sconstraint_solver$Sconstraint_solver_python_wrap.cc $(OBJ_OUT)$(OBJ_DIR)$Sswig$Sconstraint_solver_python_wrap.$O
$(LIB_DIR)/_pywrapcp.$(SWIG_LIB_SUFFIX): \

View File

@@ -11,7 +11,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#include "base/unique_ptr.h"
#include <memory>
#include "base/stringprintf.h"
#include "constraint_solver/constraint_solveri.h"
#include "constraint_solver/constraint_solver.h"

View File

@@ -1,248 +0,0 @@
// Copyright 2010-2014 Google
// 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.
// Driver to run MPSolver on MPModelProto text files.
//
// TODO(user): Move this under linear_solver/ and support more file formats and
// linear programming solvers.
#include <algorithm>
#include <cstdio>
#include <memory>
#include <string>
#include "base/commandlineflags.h"
#include "base/commandlineflags.h"
#include "base/logging.h"
#include "base/timer.h"
#include "base/filesystem.h"
#include "base/file.h"
#include "google/protobuf/message.h"
#include "google/protobuf/text_format.h"
#include "base/threadpool.h"
#include "util/gzip/gzipstring.h"
#include "glop/lp_solver.h"
#include "linear_solver/linear_solver.h"
#include "linear_solver/linear_solver.pb.h"
#include "util/fp_utils.h"
#include "util/stats.h"
#include "base/status.h"
DEFINE_string(input, "", "File pattern for problems to be optimized.");
DEFINE_bool(use_clp, false,
"Use clp. If both use_clp and use_glop are true, "
"results from both are compared.");
DEFINE_bool(use_glop, true,
"Use glop. If both use_clp and use_glop are true, "
"results from both are compared.");
DEFINE_int64(max_time_in_ms, -1, "Maximum time allowed in milliseconds.");
DEFINE_int64(threads, 1, "Number of threads.");
DEFINE_double(variable_tolerance, 1e-7, "Tolerance on variable values.");
DEFINE_double(cost_tolerance, 1e-7, "Tolerance on cost value.");
namespace operations_research {
namespace glop {
using google::protobuf::TextFormat;
struct InstanceResult {
InstanceResult()
: parsing_time_in_sec(0),
loading_time_in_sec(0),
solving_time_in_sec(0),
result_status(),
objective_value(0),
may_have_multiple_solutions(false),
variable_values() {}
double parsing_time_in_sec;
double loading_time_in_sec;
double solving_time_in_sec;
MPSolver::ResultStatus result_status;
double objective_value;
bool may_have_multiple_solutions;
std::vector<double> variable_values;
};
void Solve(MPSolver::OptimizationProblemType type, const std::string& file_name,
InstanceResult* result) {
std::string raw_data;
CHECK_OK(file::GetContents(file_name, &raw_data, file::Defaults()));
std::string uncompressed;
if (!GunzipString(raw_data, &uncompressed)) {
uncompressed = raw_data;
}
MPModelProto proto;
{
ScopedWallTime timer(&(result->parsing_time_in_sec));
if (!proto.ParseFromString(uncompressed)) {
// We do not care about timing the parsing from a text proto, that's why
// we try first to parse the proto as binary.
CHECK(TextFormat::ParseFromString(uncompressed, &proto));
}
}
MPSolver solver(file_name, type);
if (FLAGS_max_time_in_ms >= 0) {
solver.set_time_limit(FLAGS_max_time_in_ms);
}
MPSolverParameters param;
param.SetIntegerParam(MPSolverParameters::SCALING,
MPSolverParameters::SCALING_OFF);
{
ScopedWallTime timer(&(result->loading_time_in_sec));
std::string error_message;
const MPSolverResponseStatus load_status =
solver.LoadModelFromProto(proto, &error_message);
CHECK_EQ(MPSOLVER_MODEL_IS_VALID, load_status)
<< MPSolverResponseStatus_Name(load_status) << ": " << error_message;
}
{
ScopedWallTime timer(&(result->solving_time_in_sec));
result->result_status = solver.Solve(param);
}
result->objective_value = (result->result_status == MPSolver::OPTIMAL)
? solver.Objective().Value()
: 0;
int num_variables = solver.NumVariables();
result->variable_values.resize(num_variables);
std::vector<MPVariable*> variables(solver.variables());
if (result->result_status == MPSolver::OPTIMAL) {
for (int j = 0; j < num_variables; ++j) {
result->variable_values[j] = variables[j]->solution_value();
}
}
if (type == MPSolver::GLOP_LINEAR_PROGRAMMING) {
LPSolver* lp_solver = static_cast<LPSolver*>(solver.underlying_solver());
CHECK_NOTNULL(lp_solver);
result->may_have_multiple_solutions =
lp_solver->MayHaveMultipleOptimalSolutions();
}
}
void DisplayResults(const std::string& header, const std::vector<std::string>& file_list,
const std::vector<InstanceResult>& result) {
printf("Results for %s:\n", header.c_str());
TimeDistribution parsing_time_distribution("Parsing time summary");
TimeDistribution loading_time_distribution("Loading time summary");
TimeDistribution solving_time_distribution("Solving time summary");
const int size = result.size();
int num_solutions_on_facet = 0;
for (int i = 0; i < size; ++i) {
parsing_time_distribution.AddTimeInSec(result[i].parsing_time_in_sec);
loading_time_distribution.AddTimeInSec(result[i].loading_time_in_sec);
solving_time_distribution.AddTimeInSec(result[i].solving_time_in_sec);
const std::string status =
(result[i].result_status == MPSolver::OPTIMAL) ? "Optimal" : "Abnormal";
num_solutions_on_facet += result[i].may_have_multiple_solutions;
printf("%s,", file_list[i].c_str());
printf("%s,", status.c_str());
printf("%.15e,", result[i].objective_value);
printf("%f,", result[i].solving_time_in_sec);
printf("%d,", result[i].may_have_multiple_solutions);
printf("\n");
}
printf("Number of solutions on a facet: %d\n", num_solutions_on_facet);
printf("%s\n", parsing_time_distribution.StatString().c_str());
printf("%s\n", loading_time_distribution.StatString().c_str());
printf("%s\n", solving_time_distribution.StatString().c_str());
}
void Compare(const std::vector<std::string>& file_list,
const std::vector<InstanceResult>& clp_result,
const std::vector<InstanceResult>& glop_result) {
const double cost_tolerance = FLAGS_cost_tolerance;
const double variable_tolerance = FLAGS_variable_tolerance;
const int num_instances = file_list.size();
CHECK_EQ(num_instances, glop_result.size());
CHECK_EQ(num_instances, clp_result.size());
int num_differing_instances = 0;
int num_cost_differences = 0;
int num_detected_facets = 0;
operations_research::DoubleDistribution cost_delta("Cost delta summary");
for (int i = 0; i < num_instances; ++i) {
const int num_variables = glop_result[i].variable_values.size();
CHECK_EQ(num_variables, clp_result[i].variable_values.size());
bool no_difference = true;
const double glop_value = glop_result[i].objective_value;
const double clp_value = clp_result[i].objective_value;
cost_delta.Add(fabs(glop_value - clp_value) /
std::max(1.0, std::max(glop_value, clp_value)));
if (!AreWithinAbsoluteOrRelativeTolerances(
glop_result[i].objective_value, clp_result[i].objective_value,
cost_tolerance, cost_tolerance)) {
++num_cost_differences;
}
for (int var = 0; var < num_variables; ++var) {
const double glop_value = glop_result[i].variable_values[var];
const double clp_value = clp_result[i].variable_values[var];
if (no_difference &&
!AreWithinAbsoluteOrRelativeTolerances(
glop_value, clp_value, variable_tolerance, variable_tolerance)) {
no_difference = false;
++num_differing_instances;
bool multiple_solutions = glop_result[i].may_have_multiple_solutions;
num_detected_facets += multiple_solutions;
}
}
}
printf("%d instances have cost with differences >= %E.\n",
num_cost_differences, cost_tolerance);
printf("%d instances have variables with differences >= %E.\n",
num_differing_instances, variable_tolerance);
printf("%d differing solutions detected to be on a facet.\n",
num_detected_facets);
printf("%s\n", cost_delta.StatString().c_str());
}
} // namespace glop
} // namespace operations_research
using operations_research::MPSolver;
using operations_research::glop::Compare;
using operations_research::glop::DisplayResults;
using operations_research::glop::InstanceResult;
using operations_research::glop::Solve;
int main(int argc, char* argv[]) {
InitGoogle(
"Runs Glop or Clp on a given pattern of files given by --input. "
"The files must be in text proto format.",
&argc, &argv, true);
std::vector<std::string> file_list;
file::Match(FLAGS_input, &file_list, file::Defaults()).IgnoreError();
const int size = file_list.size();
std::vector<InstanceResult> clp_result(size);
std::vector<InstanceResult> glop_result(size);
{
std::unique_ptr<ThreadPool> pool(
new ThreadPool("LP_Solvers", FLAGS_threads));
pool->StartWorkers();
for (int i = 0; i < size; ++i) {
if (FLAGS_use_clp) {
pool->Add(NewCallback(&Solve, MPSolver::CLP_LINEAR_PROGRAMMING,
file_list[i], &(clp_result[i])));
}
if (FLAGS_use_glop) {
pool->Add(NewCallback(&Solve, MPSolver::GLOP_LINEAR_PROGRAMMING,
file_list[i], &(glop_result[i])));
}
}
}
if (FLAGS_use_clp) {
DisplayResults("CLP", file_list, clp_result);
}
if (FLAGS_use_glop) {
DisplayResults("Glop", file_list, glop_result);
}
if (FLAGS_use_clp && FLAGS_use_glop) {
Compare(file_list, clp_result, glop_result);
}
return EXIT_SUCCESS;
}

View File

@@ -1,50 +0,0 @@
// Copyright 2010-2014 Google
// 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.
// Utility to dump the fill-in layout of the constraint matrix of a MPS file
// to a PNG file.
#include <stdio.h>
#include <string>
#include "base/commandlineflags.h"
#include "base/commandlineflags.h"
#include "base/logging.h"
#include "base/file.h"
#include "lp_data/lp_data.h"
#include "lp_data/mps_reader.h"
#include "lp_data/png_dump.h"
#include "base/status.h"
DEFINE_string(mps_file, "", "MPS input file.");
DEFINE_string(png_file, "", "PNG output file.");
using operations_research::glop::MPSReader;
using operations_research::glop::LinearProgram;
int main(int argc, char* argv[]) {
gflags::ParseCommandLineFlags( &argc, &argv, true);
LinearProgram linear_program;
MPSReader mps_reader;
CHECK(!FLAGS_mps_file.empty());
CHECK(!FLAGS_png_file.empty());
if (mps_reader.LoadFile(FLAGS_mps_file, &linear_program)) {
std::string output = DumpConstraintMatrixToPng(linear_program);
CHECK_OK(operations_research::file::SetContents(
FLAGS_png_file, output, operations_research::file::Defaults()));
} else {
LOG(INFO) << "Parse error for " << FLAGS_mps_file;
}
return 0;
}

View File

@@ -1,53 +0,0 @@
// Copyright 2010-2014 Google
// 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 "lp_data/png_dump.h"
#include "image/base/rawimage.h"
#include "image/codec/pngencoder.h"
#include "lp_data/lp_data.h"
#include "lp_data/lp_types.h"
#include "lp_data/sparse.h"
namespace operations_research {
namespace glop {
std::string DumpConstraintMatrixToPng(const LinearProgram& linear_program) {
const ColIndex num_cols = linear_program.num_variables();
const RowIndex num_rows = linear_program.num_constraints();
image_base::RawImage image;
image.Resize(ColToIntIndex(num_cols), RowToIntIndex(num_rows),
image_base::RawImage::GRAYSCALE);
for (ColIndex col(0); col < num_cols; ++col) {
// Initialize background to white.
for (RowIndex row(0); row < num_rows; ++row) {
image.SetValue(ColToIntIndex(col), RowToIntIndex(row), 0, 255);
}
// Draw non-zero entries in black.
for (const SparseColumn::Entry e : linear_program.GetSparseColumn(col)) {
if (e.coefficient() != 0.0) {
image.SetValue(ColToIntIndex(col), RowToIntIndex(e.row()), 0, 0);
}
}
}
image_codec::PngEncoder png_encoder;
std::string output;
png_encoder.EncodeImage(&image, &output);
return output;
}
} // namespace glop
} // namespace operations_research

View File

@@ -1,31 +0,0 @@
// Copyright 2010-2014 Google
// 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.
#ifndef OR_TOOLS_LP_DATA_PNG_DUMP_H_
#define OR_TOOLS_LP_DATA_PNG_DUMP_H_
#include <string>
#include "lp_data/lp_data.h"
namespace operations_research {
namespace glop {
// Returns a PNG std::string representing the fill-in of the matrix.
std::string DumpConstraintMatrixToPng(const LinearProgram& linear_program);
} // namespace glop
} // namespace operations_research
#endif // OR_TOOLS_LP_DATA_PNG_DUMP_H_

View File

@@ -5,5 +5,6 @@ tools/generate_deps.sh GLOP glop util base linear_solver lp_data
tools/generate_deps.sh GRAPH graph base util
tools/generate_deps.sh ALGORITHMS algorithms base util graph linear_solver
tools/generate_deps.sh SAT sat base util algorithms graph linear_solver lp_data glop
tools/generate_deps.sh LP linear_solver base util glop lp_data
tools/generate_deps.sh BOP bop base util glop lp_data sat
tools/generate_deps.sh LP linear_solver base util glop lp_data bop
tools/generate_deps.sh CP constraint_solver base util graph linear_solver sat

View File

@@ -1,98 +1,134 @@
main_dir=$2
# Generate XXX_DEPS macro
echo $1_DEPS= \\
for dir in ${@:2}
do
for deps in `grep -e "\#include \"$dir" src/$dir/*.h | cut -d '"' -f 2 | sort -u`
# List all files on src/$main_dir
all_cc=`ls src/$main_dir/*.cc`
all_h=`ls src/$main_dir/*.h`
if ls src/$main_dir/*proto 1> /dev/null 2>&1; then
all_proto=`ls src/$main_dir/*.proto`
else
all_proto=
fi
# Utility functions
function src_or_gen_dir {
if [[ $1 == *\.pb\.* ]]
then
echo \$\(GEN_DIR\)/$1
else
echo \$\(SRC_DIR\)/$1
fi
}
function print_include_list {
all_deps=($1)
last_dep=${all_deps[@]:(-1)}
for dep in "${all_deps[@]}"
do
if [[ $deps == *pb.h ]]
if [[ $dep == $last_dep ]]
then
echo \ \ \ \ \$\(GEN_DIR\)/$deps \\
echo \ \ \ \ $(src_or_gen_dir $dep)
else
echo \ \ \ \ \$\(SRC_DIR\)/$deps \\
echo \ \ \ \ $(src_or_gen_dir $dep) \\
fi
done
}
function print_list_with_prefix {
all_files=($1)
last_file="${all_files[@]:(-1)}"
for file in "${all_files[@]}"
do
if [[ $file == $last_file ]]
then
echo "$2"$file
else
echo "$2"$file \\
fi
done
}
# Generate XXX_DEPS macro
all_deps_str=
for dir in ${@:2}
do
all_deps_str+=\ $(grep -e "^\#include \"$dir" src/$dir/*.h | cut -d '"' -f 2 | sort -u)
done
echo
echo $1_DEPS = \\
print_include_list "$all_deps_str"
echo
# generate XXX_LIB_OBJS macro
# generate XXX_LIB_OBJS macro.
# Get list of obj files to build.
all_cc_objs_tmp=${all_cc//src/\$\(OBJ_DIR\)}
all_cc_objs=${all_cc_objs_tmp//\.cc/\.\$O}
all_proto_objs_tmp=${all_proto//src/\$\(OBJ_DIR\)}
all_proto_objs=${all_proto_objs_tmp//\.proto/.pb.\$O}
all_objs=$all_cc_objs
all_objs+=\ $all_proto_objs
# Print makefile macro definition.
echo $1_LIB_OBJS = \\
for i in src/$2/*.cc
do
file=`basename $i .cc`
echo \ \ \ \ \$\(OBJ_DIR\)/$2/$file.\$O: \\
done
for i in src/$2/*.proto
do
if [[ -f $i ]]
then
file=`basename $i .proto`
echo \ \ \ \ \$\(OBJ_DIR\)/$2/$file.pb.\$O \\
fi
done
echo
print_list_with_prefix "$all_objs" " "
echo
# Generate dependencies for .h files
for i in src/$2/*.h
for file in $all_h
do
file=`basename $i .h`
echo \$\(SRC_DIR\)/$2/$file.h: \\
name=`basename $file .h`
# Compute dependencies.
all_deps_str=
for dir in ${@:2}
do
for deps in `grep -e "\#include \"$dir" $i | cut -d '"' -f 2`
do
if [[ $deps == *pb.h ]]
then
echo \ \ \ \ \$\(GEN_DIR\)/$deps \\
else
echo \ \ \ \ \$\(SRC_DIR\)/$deps \\
fi
done
all_deps_str+=\ $(grep -e "^\#include \"$dir" $file | cut -d '"' -f 2 | sort -u)
done
echo
echo
# Print makefile command.
if [[ ! -z ${all_deps_str// } ]]
then
echo \$\(SRC_DIR\)/$2/$name.h: \\
print_include_list "$all_deps_str"
echo
fi
done
# Generate dependencies and compilation command for .cc files
for i in src/$2/*.cc
# Generate dependencies and compilation command for .cc files.
for file in $all_cc
do
file=`basename $i .cc`
echo \$\(OBJ_DIR\)/$2/$file.\$O: \\
name=`basename $file .cc`
# Compute dependencies.
all_deps_str=
for dir in ${@:2}
do
for deps in `grep -e "\#include \"$dir" $i | cut -d '"' -f 2`
do
if [[ $deps == *pb.h ]]
then
echo \ \ \ \ \$\(GEN_DIR\)/$deps \\
else
echo \ \ \ \ \$\(SRC_DIR\)/$deps \\
fi
done
all_deps_str+=\ $(grep -e "^\#include \"$dir" $file | cut -d '"' -f 2 | sort -u)
done
echo
echo -e '\t'\$\(CCC\) \$\(CFLAGS\) -c \$\(SRC_DIR\)/$2/$file.cc \$\(OBJ_OUT\)\$\(OBJ_DIR\)\$S$2$\S$file.\$O
# Print makefile command.
echo \$\(OBJ_DIR\)/$2/$name.\$O: \\
print_include_list "$all_deps_str"
echo -e '\t'\$\(CCC\) \$\(CFLAGS\) -c \$\(SRC_DIR\)/$2/$name.cc \$\(OBJ_OUT\)\$\(OBJ_DIR\)\$S$2$\S$name.\$O
echo
done
# Generate dependencies, compulation, and protoc command for .proto files.
for i in src/$2/*proto
for file in $all_proto
do
if [[ -f $i ]]
name=`basename $file .proto`
# Compute inter proto dependencies.
all_deps_str=
for dir in ${@:2}
do
all_deps_str+=\ $(grep -e "^\import \"$dir" $file | cut -d '"' -f 2 | sed -e "s/proto/pb.h/" | sort -u)
done
# Print makefile command.
echo \$\(GEN_DIR\)/$2/$name.pb.cc: \$\(SRC_DIR\)/$2/$name.proto
echo -e '\t'\$\(PROTOBUF_DIR\)/bin/protoc --proto_path=\$\(INC_DIR\) --cpp_out=\$\(GEN_DIR\) \$\(SRC_DIR\)/$2/$name.proto
echo
if [[ ! -z ${all_deps_str// } ]]
then
file=`basename $i .proto`
echo
echo \$\(GEN_DIR\)/$2/$file.pb.cc: \$\(SRC_DIR\)/$2/$file.proto
echo -e '\t'\$\(PROTOBUF_DIR\)/bin/protoc --proto_path=\$\(INC_DIR\) --cpp_out=\$\(GEN_DIR\) \$\(SRC_DIR\)/$2/$file.proto
echo
echo \$\(GEN_DIR\)/$2/$file.pb.h: \$\(GEN_DIR\)/$2/$file.pb.cc
echo
echo \$\(OBJ_DIR\)/$2/$file.pb.\$O: \$\(GEN_DIR\)/$2/$file.pb.cc
echo -e '\t'\$\(CCC\) \$\(CFLAGS\) -c \$\(GEN_DIR\)/$2/$file.pb.cc \$\(OBJ_OUT\)\$\(OBJ_DIR\)\$S$2$\S$file.pb.\$O
echo
echo \$\(GEN_DIR\)/$2/$name.pb.h: \$\(GEN_DIR\)/$2/$name.pb.cc \\
print_include_list "$all_deps_str"
else
echo \$\(GEN_DIR\)/$2/$name.pb.h: \$\(GEN_DIR\)/$2/$name.pb.cc
fi
echo
echo \$\(OBJ_DIR\)/$2/$name.pb.\$O: \$\(GEN_DIR\)/$2/$name.pb.cc
echo -e '\t'\$\(CCC\) \$\(CFLAGS\) -c \$\(GEN_DIR\)/$2/$name.pb.cc \$\(OBJ_OUT\)\$\(OBJ_DIR\)\$S$2$\S$name.pb.\$O
echo
done
#TODO: Generate inter-proto dependencies.