Commit 838cf146 authored by Tudor Bosman's avatar Tudor Bosman Committed by facebook-github-bot-1

Make gflags and boost::program_options play nice with each other

Summary: GFlags is useful for global program options. boost::program_options makes it
easier to write command-line utilities. They don't, unfortunately, play
very nicely with each other.

Add a addGFlags() function to convert all GFlags to boost::program_options
options; you can then use boost::program_options::parse_command_line() to
parse all arguments, GFlags or not.

Also add a helper function to make parsing nested command lines easier.

Reviewed By: @fugalh

Differential Revision: D2215285
parent 7334598f
...@@ -111,6 +111,7 @@ nobase_follyinclude_HEADERS = \ ...@@ -111,6 +111,7 @@ nobase_follyinclude_HEADERS = \
experimental/io/FsUtil.h \ experimental/io/FsUtil.h \
experimental/JSONSchema.h \ experimental/JSONSchema.h \
experimental/LockFreeRingBuffer.h \ experimental/LockFreeRingBuffer.h \
experimental/ProgramOptions.h \
experimental/Select64.h \ experimental/Select64.h \
experimental/StringKeyedCommon.h \ experimental/StringKeyedCommon.h \
experimental/StringKeyedUnorderedMap.h \ experimental/StringKeyedUnorderedMap.h \
...@@ -371,6 +372,7 @@ libfolly_la_SOURCES = \ ...@@ -371,6 +372,7 @@ libfolly_la_SOURCES = \
experimental/FunctionScheduler.cpp \ experimental/FunctionScheduler.cpp \
experimental/io/FsUtil.cpp \ experimental/io/FsUtil.cpp \
experimental/JSONSchema.cpp \ experimental/JSONSchema.cpp \
experimental/ProgramOptions.cpp \
experimental/Select64.cpp \ experimental/Select64.cpp \
experimental/TestUtil.cpp experimental/TestUtil.cpp
......
...@@ -107,8 +107,9 @@ AC_CHECK_LIB(ssl, ...@@ -107,8 +107,9 @@ AC_CHECK_LIB(ssl,
# check for boost libs # check for boost libs
AX_BOOST_BASE([1.51.0], [], [AC_MSG_ERROR( AX_BOOST_BASE([1.51.0], [], [AC_MSG_ERROR(
[Please install boost >= 1.51.0 (context, thread, regex, and system)])]) [Please install boost >= 1.51.0 (context, thread, program_options, regex, and system)])])
AX_BOOST_CONTEXT AX_BOOST_CONTEXT
AX_BOOST_PROGRAM_OPTIONS
AX_BOOST_THREAD AX_BOOST_THREAD
AX_BOOST_REGEX AX_BOOST_REGEX
AX_BOOST_SYSTEM AX_BOOST_SYSTEM
......
/*
* Copyright 2015 Facebook, Inc.
*
* 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 <folly/experimental/ProgramOptions.h>
#include <unordered_map>
#include <unordered_set>
#include <gflags/gflags.h>
#include <glog/logging.h>
#include <folly/Conv.h>
#include <folly/Portability.h>
namespace po = ::boost::program_options;
namespace folly {
namespace {
// Information about one GFlag. Handled via shared_ptr, as, in the case
// of boolean flags, two boost::program_options options (--foo and --nofoo)
// may share the same GFlag underneath.
//
// We're slightly abusing the boost::program_options interface; the first
// time we (successfully) parse a value that matches this GFlag, we'll set
// it and remember not to set it again; this prevents, for example, the
// default value of --foo from overwriting the GFlag if --nofoo is set.
template <class T>
class GFlagInfo {
public:
explicit GFlagInfo(gflags::CommandLineFlagInfo info)
: info_(std::move(info)),
isSet_(false) { }
void set(const T& value) {
if (isSet_) {
return;
}
auto strValue = folly::to<std::string>(value);
auto msg = gflags::SetCommandLineOption(
info_.name.c_str(),
strValue.c_str());
if (msg.empty()) {
throw po::invalid_option_value(strValue);
}
isSet_ = true;
}
T get() const {
std::string str;
CHECK(gflags::GetCommandLineOption(info_.name.c_str(), &str));
return folly::to<T>(str);
}
const gflags::CommandLineFlagInfo& info() const { return info_; }
private:
gflags::CommandLineFlagInfo info_;
bool isSet_;
};
template <class T>
class GFlagValueSemanticBase : public po::value_semantic {
public:
explicit GFlagValueSemanticBase(std::shared_ptr<GFlagInfo<T>> info)
: info_(std::move(info)) { }
std::string name() const override { return "arg"; }
bool is_composing() const override { return false; }
bool is_required() const override { return false; }
// We handle setting the GFlags from parse(), so notify() does nothing.
void notify(const boost::any& valueStore) const override { }
bool apply_default(boost::any& valueStore) const override {
// We're using the *current* rather than *default* value here, and
// this is intentional; GFlags-using programs assign to FLAGS_foo
// before ParseCommandLineFlags() in order to change the default value,
// and we obey that.
auto val = info_->get();
this->transform(val);
valueStore = val;
return true;
}
void parse(boost::any& valueStore,
const std::vector<std::string>& tokens,
bool utf8) const override;
private:
virtual T parseValue(const std::vector<std::string>& tokens) const = 0;
virtual void transform(T& val) const { }
mutable std::shared_ptr<GFlagInfo<T>> info_;
};
template <class T>
void GFlagValueSemanticBase<T>::parse(boost::any& valueStore,
const std::vector<std::string>& tokens,
bool utf8) const {
T val;
try {
val = this->parseValue(tokens);
this->transform(val);
} catch (const std::exception& e) {
throw po::invalid_option_value(
tokens.empty() ? std::string() : tokens.front());
}
this->info_->set(val);
valueStore = val;
}
template <class T>
class GFlagValueSemantic : public GFlagValueSemanticBase<T> {
public:
explicit GFlagValueSemantic(std::shared_ptr<GFlagInfo<T>> info)
: GFlagValueSemanticBase<T>(std::move(info)) { }
unsigned min_tokens() const override { return 1; }
unsigned max_tokens() const override { return 1; }
T parseValue(const std::vector<std::string>& tokens) const override {
DCHECK(tokens.size() == 1);
return folly::to<T>(tokens.front());
}
};
class BoolGFlagValueSemantic : public GFlagValueSemanticBase<bool> {
public:
explicit BoolGFlagValueSemantic(std::shared_ptr<GFlagInfo<bool>> info)
: GFlagValueSemanticBase<bool>(std::move(info)) { }
unsigned min_tokens() const override { return 0; }
unsigned max_tokens() const override { return 0; }
bool parseValue(const std::vector<std::string>& tokens) const override {
DCHECK(tokens.empty());
return true;
}
};
class NegativeBoolGFlagValueSemantic : public BoolGFlagValueSemantic {
public:
explicit NegativeBoolGFlagValueSemantic(std::shared_ptr<GFlagInfo<bool>> info)
: BoolGFlagValueSemantic(std::move(info)) { }
private:
void transform(bool& val) const override {
val = !val;
}
};
static const std::unordered_set<std::string> gSkipFlags {
"flagfile",
"fromenv",
"tryfromenv",
"undefok",
"help",
"helpfull",
"helpshort",
"helpon",
"helpmatch",
"helppackage",
"helpxml",
"version",
"tab_completion_columns",
"tab_completion_word",
};
static const std::unordered_map<std::string, std::string> gFlagOverrides {
// Allow -v in addition to --v
{"v", "v,v"},
};
const std::string& getName(const std::string& name) {
auto pos = gFlagOverrides.find(name);
return pos != gFlagOverrides.end() ? pos->second : name;
}
template <class T>
void addGFlag(gflags::CommandLineFlagInfo&& flag,
po::options_description& desc,
ProgramOptionsStyle style) {
auto gflagInfo = std::make_shared<GFlagInfo<T>>(std::move(flag));
auto& info = gflagInfo->info();
auto name = getName(info.name);
switch (style) {
case ProgramOptionsStyle::GFLAGS:
break;
case ProgramOptionsStyle::GNU:
std::replace(name.begin(), name.end(), '_', '-');
break;
}
desc.add_options()
(name.c_str(),
new GFlagValueSemantic<T>(gflagInfo),
info.description.c_str());
}
template <>
void addGFlag<bool>(gflags::CommandLineFlagInfo&& flag,
po::options_description& desc,
ProgramOptionsStyle style) {
auto gflagInfo = std::make_shared<GFlagInfo<bool>>(std::move(flag));
auto& info = gflagInfo->info();
auto name = getName(info.name);
std::string negationPrefix;
switch (style) {
case ProgramOptionsStyle::GFLAGS:
negationPrefix = "no";
break;
case ProgramOptionsStyle::GNU:
std::replace(name.begin(), name.end(), '_', '-');
negationPrefix = "no-";
break;
}
desc.add_options()
(name.c_str(),
new BoolGFlagValueSemantic(gflagInfo),
info.description.c_str())
((negationPrefix + name).c_str(),
new NegativeBoolGFlagValueSemantic(gflagInfo),
folly::to<std::string>("(no) ", info.description).c_str());
}
typedef void(*FlagAdder)(gflags::CommandLineFlagInfo&&,
po::options_description&,
ProgramOptionsStyle);
const std::unordered_map<std::string, FlagAdder> gFlagAdders = {
#define X(NAME, TYPE) \
{NAME, addGFlag<TYPE>},
X("bool", bool)
X("int32", int32_t)
X("int64", int64_t)
X("uint64", uint64_t)
X("double", double)
X("string", std::string)
#undef X
};
} // namespace
po::options_description getGFlags(ProgramOptionsStyle style) {
po::options_description desc("GFlags");
std::vector<gflags::CommandLineFlagInfo> allFlags;
gflags::GetAllFlags(&allFlags);
for (auto& f : allFlags) {
if (gSkipFlags.count(f.name)) {
continue;
}
auto pos = gFlagAdders.find(f.type);
CHECK(pos != gFlagAdders.end()) << "Invalid flag type: " << f.type;
(*pos->second)(std::move(f), desc, style);
}
return desc;
}
namespace {
NestedCommandLineParseResult doParseNestedCommandLine(
po::command_line_parser&& parser,
const po::options_description& desc) {
NestedCommandLineParseResult result;
result.options = parser.options(desc).allow_unregistered().run();
bool setCommand = true;
for (auto& opt : result.options.options) {
auto& tokens = opt.original_tokens;
auto tokensStart = tokens.begin();
if (setCommand && opt.position_key != -1) {
DCHECK(tokensStart != tokens.end());
result.command = *(tokensStart++);
}
if (opt.position_key != -1 || opt.unregistered) {
// If we see an unrecognized option before the first positional
// argument, assume we don't have a valid command name, because
// we don't know how to parse it otherwise.
//
// program --wtf foo bar
//
// Is "foo" an argument to "--wtf", or the command name?
setCommand = false;
result.rest.insert(result.rest.end(), tokensStart, tokens.end());
}
}
return result;
}
} // namespace
NestedCommandLineParseResult parseNestedCommandLine(
int argc, const char* const argv[],
const po::options_description& desc) {
return doParseNestedCommandLine(po::command_line_parser(argc, argv), desc);
}
NestedCommandLineParseResult parseNestedCommandLine(
const std::vector<std::string>& cmdline,
const po::options_description& desc) {
return doParseNestedCommandLine(po::command_line_parser(cmdline), desc);
}
} // namespaces
/*
* Copyright 2015 Facebook, Inc.
*
* 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 FOLLY_PROGRAMOPTIONS_H_
#define FOLLY_PROGRAMOPTIONS_H_
#include <boost/program_options.hpp>
#include <folly/Optional.h>
#include <gflags/gflags.h>
namespace folly {
enum class ProgramOptionsStyle {
GFLAGS,
GNU
};
// Add all GFlags to the given options_description.
// Use this *instead of* gflags::ParseCommandLineFlags().
//
// in GFLAGS style, the flags are named as per gflags conventions:
// names_with_underscores
// boolean flags have a "no" prefix
//
// in GNU style, the flags are named as per GNU conventions:
// names-with-dashes
// boolean flags have a "no-" prefix
//
// Consider (for example) a boolean flag:
// DEFINE_bool(flying_pigs, false, "...");
//
// In GFLAGS style, the corresponding flags are named
// flying_pigs
// noflying_pigs
//
// In GNU style, the corresponding flags are named
// flying-pigs
// no-flying-pigs
//
// You may not pass arguments to boolean flags, so you must use the
// "no" / "no-" prefix to set them to false; "--flying_pigs false"
// and "--flying_pigs=false" are not allowed, to prevent ambiguity.
boost::program_options::options_description getGFlags(
ProgramOptionsStyle style = ProgramOptionsStyle::GNU);
// Helper when parsing nested command lines:
//
// program [--common_options...] command [--command_options...] args
//
// The result has "command" set to the first positional argument, if any,
// and "rest" set to the remaining options and arguments. Note that any
// unrecognized flags must appear after the command name.
//
// You may pass "rest" to parseNestedCommandLine again, etc.
struct NestedCommandLineParseResult {
NestedCommandLineParseResult() { }
boost::program_options::parsed_options options {nullptr};
Optional<std::string> command;
std::vector<std::string> rest;
};
NestedCommandLineParseResult parseNestedCommandLine(
int argc, const char* const argv[],
const boost::program_options::options_description& desc);
NestedCommandLineParseResult parseNestedCommandLine(
const std::vector<std::string>& cmdline,
const boost::program_options::options_description& desc);
} // namespaces
#endif /* FOLLY_PROGRAMOPTIONS_H_ */
/*
* Copyright 2015 Facebook, Inc.
*
* 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 <folly/experimental/ProgramOptions.h>
#include <folly/FileUtil.h>
#include <folly/Subprocess.h>
#include <folly/experimental/io/FsUtil.h>
#include <glog/logging.h>
#include <gtest/gtest.h>
namespace folly { namespace test {
namespace {
std::string getHelperPath() {
auto path = fs::executable_path();
path.remove_filename() /= "program_options_test_helper";
return path.native();
}
std::string callHelper(ProgramOptionsStyle style,
std::initializer_list<std::string> args) {
static std::string helperPath = getHelperPath();
std::vector<std::string> allArgs;
allArgs.reserve(args.size() + 1);
allArgs.push_back(helperPath);
allArgs.insert(allArgs.end(), args.begin(), args.end());
std::vector<std::string> env;
switch (style) {
case ProgramOptionsStyle::GNU:
env.push_back("PROGRAM_OPTIONS_TEST_STYLE=GNU");
break;
case ProgramOptionsStyle::GFLAGS:
env.push_back("PROGRAM_OPTIONS_TEST_STYLE=GFLAGS");
break;
}
Subprocess proc(allArgs, Subprocess::pipeStdout(), nullptr, &env);
auto p = proc.communicate();
EXPECT_EQ(0, proc.wait().exitStatus());
return p.first;
}
} // namespace
// name value
TEST(ProgramOptionsTest, GFlagsStyleDefaultValues) {
EXPECT_EQ(
"flag_bool_true 1\n"
"flag_bool_false 0\n"
"flag_int 42\n"
"flag_string foo\n",
callHelper(ProgramOptionsStyle::GFLAGS, {}));
}
TEST(ProgramOptionsTest, GFlagsStyleFlagsSet) {
EXPECT_EQ(
"flag_bool_true 1\n"
"flag_bool_false 1\n"
"flag_int 43\n"
"flag_string bar\n",
callHelper(ProgramOptionsStyle::GFLAGS, {
"--flag_bool_true",
"--flag_bool_false",
"--flag_int", "43",
"--flag_string", "bar"}));
}
TEST(ProgramOptionsTest, GFlagsStyleBoolFlagsNegation) {
EXPECT_EQ(
"flag_bool_true 0\n"
"flag_bool_false 0\n"
"flag_int 42\n"
"flag_string foo\n",
callHelper(ProgramOptionsStyle::GFLAGS, {
"--noflag_bool_true",
"--noflag_bool_false"}));
}
TEST(ProgramOptionsTest, GNUStyleDefaultValues) {
EXPECT_EQ(
"flag-bool-true 1\n"
"flag-bool-false 0\n"
"flag-int 42\n"
"flag-string foo\n",
callHelper(ProgramOptionsStyle::GNU, {}));
}
TEST(ProgramOptionsTest, GNUStyleFlagsSet) {
EXPECT_EQ(
"flag-bool-true 1\n"
"flag-bool-false 1\n"
"flag-int 43\n"
"flag-string bar\n",
callHelper(ProgramOptionsStyle::GNU, {
"--flag-bool-true",
"--flag-bool-false",
"--flag-int", "43",
"--flag-string", "bar"}));
}
TEST(ProgramOptionsTest, GNUStyleBoolFlagsNegation) {
EXPECT_EQ(
"flag-bool-true 0\n"
"flag-bool-false 0\n"
"flag-int 42\n"
"flag-string foo\n",
callHelper(ProgramOptionsStyle::GNU, {
"--no-flag-bool-true",
"--no-flag-bool-false"}));
}
TEST(ProgramOptionsTest, GNUStyleSubCommand) {
EXPECT_EQ(
"flag-bool-true 1\n"
"flag-bool-false 1\n"
"flag-int 43\n"
"flag-string foo\n"
"command hello\n"
"arg --wtf\n"
"arg 100\n"
"arg -x\n"
"arg -xy\n",
callHelper(ProgramOptionsStyle::GNU, {
"--flag-bool-false",
"hello",
"--wtf",
"--flag-int", "43",
"100",
"-x",
"-xy"}));
}
TEST(ProgramOptionsTest, GNUStyleSubCommandUnrecognizedOptionFirst) {
EXPECT_EQ(
"flag-bool-true 1\n"
"flag-bool-false 1\n"
"flag-int 43\n"
"flag-string foo\n"
"arg --wtf\n"
"arg hello\n"
"arg 100\n"
"arg -x\n"
"arg -xy\n",
callHelper(ProgramOptionsStyle::GNU, {
"--flag-bool-false",
"--wtf",
"hello",
"--flag-int", "43",
"100",
"-x",
"-xy"}));
}
}} // namespaces
/*
* Copyright 2015 Facebook, Inc.
*
* 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 <folly/Conv.h>
#include <folly/experimental/ProgramOptions.h>
#include <glog/logging.h>
DEFINE_bool(flag_bool_true, true, "Bool with true default value");
DEFINE_bool(flag_bool_false, false, "Bool with false default value");
DEFINE_int32(flag_int, 42, "Integer flag");
DEFINE_string(flag_string, "foo", "String flag");
namespace po = ::boost::program_options;
namespace {
template <class T>
void print(const po::variables_map& vm, const std::string& name) {
auto& v = vm[name];
printf("%s %s\n",
name.c_str(),
folly::to<std::string>(v.as<T>()).c_str());
}
} // namespace
int main(int argc, char *argv[]) {
po::options_description desc;
auto styleEnv = getenv("PROGRAM_OPTIONS_TEST_STYLE");
CHECK(styleEnv) << "PROGRAM_OPTIONS_TEST_STYLE is required";
bool gnuStyle = !strcmp(styleEnv, "GNU");
CHECK(gnuStyle || !strcmp(styleEnv, "GFLAGS"))
<< "Invalid value for PROGRAM_OPTIONS_TEST_STYLE";
desc.add(getGFlags(
gnuStyle ? folly::ProgramOptionsStyle::GNU :
folly::ProgramOptionsStyle::GFLAGS));
desc.add_options()
("help,h", "help");
po::variables_map vm;
auto result = folly::parseNestedCommandLine(argc, argv, desc);
po::store(result.options, vm);
po::notify(vm);
if (vm.count("help")) {
std::cout << desc;
return 1;
}
print<bool>(vm, gnuStyle ? "flag-bool-true" : "flag_bool_true");
print<bool>(vm, gnuStyle ? "flag-bool-false" : "flag_bool_false");
print<int32_t>(vm, gnuStyle ? "flag-int" : "flag_int");
print<std::string>(vm, gnuStyle ? "flag-string" : "flag_string");
if (result.command) {
printf("command %s\n", result.command->c_str());
}
for (auto& arg : result.rest) {
printf("arg %s\n", arg.c_str());
}
return 0;
}
# ============================================================================
# http://www.gnu.org/software/autoconf-archive/ax_boost_program_options.html
# ============================================================================
#
# SYNOPSIS
#
# AX_BOOST_PROGRAM_OPTIONS
#
# DESCRIPTION
#
# Test for program options library from the Boost C++ libraries. The macro
# requires a preceding call to AX_BOOST_BASE. Further documentation is
# available at <http://randspringer.de/boost/index.html>.
#
# This macro calls:
#
# AC_SUBST(BOOST_PROGRAM_OPTIONS_LIB)
#
# And sets:
#
# HAVE_BOOST_PROGRAM_OPTIONS
#
# LICENSE
#
# Copyright (c) 2009 Thomas Porschberg <thomas@randspringer.de>
#
# Copying and distribution of this file, with or without modification, are
# permitted in any medium without royalty provided the copyright notice
# and this notice are preserved. This file is offered as-is, without any
# warranty.
#serial 24
AC_DEFUN([AX_BOOST_PROGRAM_OPTIONS],
[
AC_ARG_WITH([boost-program-options],
AS_HELP_STRING([--with-boost-program-options@<:@=special-lib@:>@],
[use the program options library from boost - it is possible to specify a certain library for the linker
e.g. --with-boost-program-options=boost_program_options-gcc-mt-1_33_1 ]),
[
if test "$withval" = "no"; then
want_boost="no"
elif test "$withval" = "yes"; then
want_boost="yes"
ax_boost_user_program_options_lib=""
else
want_boost="yes"
ax_boost_user_program_options_lib="$withval"
fi
],
[want_boost="yes"]
)
if test "x$want_boost" = "xyes"; then
AC_REQUIRE([AC_PROG_CC])
export want_boost
CPPFLAGS_SAVED="$CPPFLAGS"
CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS"
export CPPFLAGS
LDFLAGS_SAVED="$LDFLAGS"
LDFLAGS="$LDFLAGS $BOOST_LDFLAGS"
export LDFLAGS
AC_CACHE_CHECK([whether the Boost::Program_Options library is available],
ax_cv_boost_program_options,
[AC_LANG_PUSH(C++)
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[@%:@include <boost/program_options/errors.hpp>
]],
[[boost::program_options::error err("Error message");
return 0;]])],
ax_cv_boost_program_options=yes, ax_cv_boost_program_options=no)
AC_LANG_POP([C++])
])
if test "$ax_cv_boost_program_options" = yes; then
AC_DEFINE(HAVE_BOOST_PROGRAM_OPTIONS,,[define if the Boost::PROGRAM_OPTIONS library is available])
BOOSTLIBDIR=`echo $BOOST_LDFLAGS | sed -e 's/@<:@^\/@:>@*//'`
if test "x$ax_boost_user_program_options_lib" = "x"; then
for libextension in `ls $BOOSTLIBDIR/libboost_program_options*.so* 2>/dev/null | sed 's,.*/,,' | sed -e 's;^lib\(boost_program_options.*\)\.so.*$;\1;'` `ls $BOOSTLIBDIR/libboost_program_options*.dylib* 2>/dev/null | sed 's,.*/,,' | sed -e 's;^lib\(boost_program_options.*\)\.dylib.*$;\1;'` `ls $BOOSTLIBDIR/libboost_program_options*.a* 2>/dev/null | sed 's,.*/,,' | sed -e 's;^lib\(boost_program_options.*\)\.a.*$;\1;'` ; do
ax_lib=${libextension}
AC_CHECK_LIB($ax_lib, exit,
[BOOST_PROGRAM_OPTIONS_LIB="-l$ax_lib"; AC_SUBST(BOOST_PROGRAM_OPTIONS_LIB) link_program_options="yes"; break],
[link_program_options="no"])
done
if test "x$link_program_options" != "xyes"; then
for libextension in `ls $BOOSTLIBDIR/boost_program_options*.dll* 2>/dev/null | sed 's,.*/,,' | sed -e 's;^\(boost_program_options.*\)\.dll.*$;\1;'` `ls $BOOSTLIBDIR/boost_program_options*.a* 2>/dev/null | sed 's,.*/,,' | sed -e 's;^\(boost_program_options.*\)\.a.*$;\1;'` ; do
ax_lib=${libextension}
AC_CHECK_LIB($ax_lib, exit,
[BOOST_PROGRAM_OPTIONS_LIB="-l$ax_lib"; AC_SUBST(BOOST_PROGRAM_OPTIONS_LIB) link_program_options="yes"; break],
[link_program_options="no"])
done
fi
else
for ax_lib in $ax_boost_user_program_options_lib boost_program_options-$ax_boost_user_program_options_lib; do
AC_CHECK_LIB($ax_lib, main,
[BOOST_PROGRAM_OPTIONS_LIB="-l$ax_lib"; AC_SUBST(BOOST_PROGRAM_OPTIONS_LIB) link_program_options="yes"; break],
[link_program_options="no"])
done
fi
if test "x$ax_lib" = "x"; then
AC_MSG_ERROR(Could not find a version of the library!)
fi
if test "x$link_program_options" != "xyes"; then
AC_MSG_ERROR([Could not link against [$ax_lib] !])
fi
fi
CPPFLAGS="$CPPFLAGS_SAVED"
LDFLAGS="$LDFLAGS_SAVED"
fi
])
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment