1/* A program to enquire about the configuration of the PPL -*- C++ -*- 2 and of the applications using it. 3 Copyright (C) 2001-2010 Roberto Bagnara <bagnara@cs.unipr.it> 4 Copyright (C) 2010-2016 BUGSENG srl (http://bugseng.com) 5 6This file is part of the Parma Polyhedra Library (PPL). 7 8The PPL is free software; you can redistribute it and/or modify it 9under the terms of the GNU General Public License as published by the 10Free Software Foundation; either version 3 of the License, or (at your 11option) any later version. 12 13The PPL is distributed in the hope that it will be useful, but WITHOUT 14ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 15FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 16for more details. 17 18You should have received a copy of the GNU General Public License 19along with this program; if not, write to the Free Software Foundation, 20Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1307, USA. 21 22For the most up-to-date information see the Parma Polyhedra Library 23site: http://bugseng.com/products/ppl/ . */ 24 25#include "ppl.hh" 26#include "BUGS.hh" 27#include "COPYING.hh" 28#include "CREDITS.hh" 29 30namespace PPL = Parma_Polyhedra_Library; 31 32#if PPL_VERSION_MAJOR == 0 && PPL_VERSION_MINOR < 8 33#error "PPL version 0.8 or following is required" 34#endif 35 36#include <cstdarg> 37#include <cstring> 38#include <cctype> 39#include <cstdio> 40#include <cstdlib> 41#include <iostream> 42#include <stdexcept> 43#include <string> 44 45#ifdef PPL_HAVE_GETOPT_H 46#include <getopt.h> 47 48// Try to accommodate non-GNU implementations of `getopt()'. 49#if !defined(no_argument) && defined(NO_ARG) 50#define no_argument NO_ARG 51#endif 52 53#if !defined(required_argument) && defined(REQUIRED_ARG) 54#define required_argument REQUIRED_ARG 55#endif 56 57#if !defined(optional_argument) && defined(OPTIONAL_ARG) 58#define optional_argument OPTIONAL_ARG 59#endif 60 61#endif // defined(PPL_HAVE_GETOPT_H) 62 63#ifdef PPL_HAVE_UNISTD_H 64// Include this for `getopt()': especially important if we do not have 65// <getopt.h>. 66#include <unistd.h> 67#endif 68 69 70namespace { 71 72enum Format { 73 NO_FORMAT, 74 PLAIN, 75 MAKEFILE, 76 SH, 77 CSH 78}; 79 80enum Interface { 81 NO_INTERFACE, 82 CXX, 83 C, 84 CIAO_PROLOG, 85 GNU_PROLOG, 86 SICSTUS_PROLOG, 87 SWI_PROLOG, 88 XSB_PROLOG, 89 YAP_PROLOG, 90 OCAML, 91 JAVA 92}; 93 94Format required_format = NO_FORMAT; 95 96Interface required_interface = NO_INTERFACE; 97 98#define PPL_LICENSE "GNU GENERAL PUBLIC LICENSE, Version 3" 99 100std::string prefix; 101std::string exec_prefix; 102 103bool required_application = false; 104bool required_library = false; 105bool required_prefix = false; 106bool required_exec_prefix = false; 107bool required_configure_options = false; 108bool required_version = false; 109bool required_version_major = false; 110bool required_version_minor = false; 111bool required_version_revision = false; 112bool required_version_beta = false; 113bool required_banner = false; 114bool required_coefficients = false; 115bool required_includedir = false; 116bool required_bindir = false; 117bool required_libdir = false; 118bool required_cppflags = false; 119bool required_cflags = false; 120bool required_cxxflags = false; 121bool required_ldflags = false; 122bool required_license = false; 123bool required_copying = false; 124bool required_bugs = false; 125bool required_credits = false; 126 127unsigned num_required_items = 0; 128 129 130#define OPTION_LETTERS "hF:I:ALp::e::OVMNRBEniblPCXDgcur" 131 132const char* program_name = 0; 133 134void 135fatal(const char* format, ...) __attribute__((__noreturn__)); 136 137void 138fatal(const char* format, ...) { 139 va_list ap; 140 va_start(ap, format); 141 fprintf(stderr, "%s: ", program_name); 142 vfprintf(stderr, format, ap); 143 fprintf(stderr, "\n"); 144 va_end(ap); 145 exit(1); 146} 147 148void 149internal_error() __attribute__((__noreturn__)); 150 151void 152internal_error() { 153 fatal("internal error: please submit a bug report to ppl-devel@cs.unipr.it"); 154} 155 156inline char 157to_lower(char c) { 158 return 159 static_cast<char>(tolower(static_cast<int>(static_cast<unsigned char>(c)))); 160} 161 162bool 163strcaseeq(const char* s1, const char* s2) { 164 while (*s1 != '\0') { 165 if (*s2 == '\0' || to_lower(*s1) != to_lower(*s2)) 166 return false; 167 ++s1; 168 ++s2; 169 } 170 return *s2 == '\0'; 171} 172 173void 174process_options(int argc, char* argv[]) { 175 176 bool exec_prefix_set = false; 177 178#ifdef PPL_HAVE_GETOPT_H 179struct option long_options[] = { 180 {"help", no_argument, 0, 'h'}, 181 {"format", required_argument, 0, 'F'}, 182 {"interface", required_argument, 0, 'I'}, 183 {"application", no_argument, 0, 'A'}, 184 {"library", no_argument, 0, 'L'}, 185 {"prefix", optional_argument, 0, 'p'}, 186 {"exec-prefix", optional_argument, 0, 'e'}, 187 {"configure-options", no_argument, 0, 'O'}, 188 {"version", no_argument, 0, 'V'}, 189 {"version-major", no_argument, 0, 'M'}, 190 {"version-minor", no_argument, 0, 'N'}, 191 {"version-revision", no_argument, 0, 'R'}, 192 {"version-beta", no_argument, 0, 'B'}, 193 {"banner", no_argument, 0, 'E'}, 194 {"coefficients", no_argument, 0, 'n'}, 195 {"includedir", no_argument, 0, 'i'}, 196 {"bindir", no_argument, 0, 'b'}, 197 {"libdir", no_argument, 0, 'l'}, 198 {"cppflags", no_argument, 0, 'P'}, 199 {"cflags", no_argument, 0, 'C'}, 200 {"cxxflags", no_argument, 0, 'X'}, 201 {"ldflags", no_argument, 0, 'D'}, 202 {"license", no_argument, 0, 'g'}, 203 {"copying", no_argument, 0, 'c'}, 204 {"bugs", no_argument, 0, 'u'}, 205 {"credits", no_argument, 0, 'r'}, 206 {0, 0, 0, 0} 207}; 208#endif 209 210 static const char* usage_string 211 = "Usage: %s [OPTION]...\n" 212"Displays information, in various formats, about an installation\n" 213"of the Parma Polyhedra Library.\n\n" 214"Options:\n" 215" -h, --help prints this help text to stdout\n" 216" -FFMT, --format=FMT sets the output format to FMT\n" 217" (one of `plain', `makefile', `sh' or `csh')\n" 218" -IINT, --interface=INT selects a library interface (one of `C++', `C',\n" 219" `Ciao-Prolog', `GNU-Prolog', `SICStus-Prolog',\n" 220" `SWI-Prolog', `XSB-Prolog', `YAP-Prolog',\n" 221" `OCaml' or `Java')\n" 222" -A, --application selects output for building an application\n" 223" -L, --library selects output for building a library\n" 224" -p[PFX], --prefix[=PFX] prints or sets library prefix information\n" 225" -e[PFX], --exec-prefix[=PFX]\n" 226" prints or sets library exec-prefix information\n" 227" -O, --configure-options prints configuration options\n" 228" -V, --version prints version information\n" 229" -M, --version-major prints version major number\n" 230" -N, --version-minor prints version minor number\n" 231" -R, --version-revision prints version revision number\n" 232" -B, --version-beta prints version beta number\n" 233" -E, --banner prints library banner\n" 234" -n, --coefficients prints type of library coefficients\n" 235" -i, --includedir prints include files directory\n" 236" -b, --bindir prints binary executables directory\n" 237" -l, --libdir prints library files directory\n" 238" -P, --cppflags prints preprocessor flags\n" 239" -C, --cflags prints C compiler flags\n" 240" -X, --cxxflags prints C++ compiler flags\n" 241" -D, --ldflags prints linker flags\n" 242" -g, --license prints synthetic licensing information\n" 243" -c, --copying prints detailed licensing information\n" 244" -u, --bugs prints bug reporting information\n" 245" -r, --credits prints credits\n" 246#ifndef PPL_HAVE_GETOPT_H 247"\n" 248"NOTE: this version does not support long options.\n" 249#endif 250"\n" 251"Report bugs to <ppl-devel@cs.unipr.it>.\n"; 252 253 while (true) { 254#ifdef PPL_HAVE_GETOPT_H 255 int option_index = 0; 256 int c = getopt_long(argc, argv, OPTION_LETTERS, long_options, 257 &option_index); 258#else 259 int c = getopt(argc, argv, OPTION_LETTERS); 260#endif 261 262 if (c == EOF) 263 break; 264 265 switch (c) { 266 case 0: 267 break; 268 269 case '?': 270 case 'h': 271 fprintf(stdout, usage_string, argv[0]); 272 exit(0); 273 break; 274 275 // --format 276 case 'F': 277 if (strcaseeq(optarg, "plain")) 278 required_format = PLAIN; 279 else if (strcaseeq(optarg, "makefile")) 280 required_format = MAKEFILE; 281 else if (strcaseeq(optarg, "sh")) 282 required_format = SH; 283 else if (strcaseeq(optarg, "csh")) 284 required_format = CSH; 285 else 286 fatal("invalid argument `%s' to --format: " 287 "must be `plain', `makefile', `sh' or `csh'", 288 optarg); 289 break; 290 291 // --interface 292 case 'I': 293 if (strcaseeq(optarg, "C++")) 294 required_interface = CXX; 295 else if (strcaseeq(optarg, "C")) 296 required_interface = C; 297 else if (strcaseeq(optarg, "Ciao-Prolog")) 298 required_interface = CIAO_PROLOG; 299 else if (strcaseeq(optarg, "GNU-Prolog")) 300 required_interface = GNU_PROLOG; 301 else if (strcaseeq(optarg, "SICStus-Prolog")) 302 required_interface = SICSTUS_PROLOG; 303 else if (strcaseeq(optarg, "SWI-Prolog")) 304 required_interface = SWI_PROLOG; 305 else if (strcaseeq(optarg, "XSB-Prolog")) 306 required_interface = XSB_PROLOG; 307 else if (strcaseeq(optarg, "YAP-Prolog")) 308 required_interface = YAP_PROLOG; 309 else if (strcaseeq(optarg, "OCaml")) 310 required_interface = OCAML; 311 else if (strcaseeq(optarg, "Java")) 312 required_interface = JAVA; 313 else 314 fatal("invalid argument `%s' to --interface: " 315 "must be `C++', `C', `Ciao-Prolog', `GNU-Prolog', " 316 "`SICStus-Prolog', `SWI-Prolog', `XSB-Prolog', `YAP-Prolog', " 317 "`OCaml' or `Java'", 318 optarg); 319 break; 320 321 // --application 322 case 'A': 323 required_application = true; 324 break; 325 326 // --library 327 case 'L': 328 required_library = true; 329 break; 330 331 // --prefix 332 case 'p': 333 if (optarg != 0) { 334 prefix = optarg; 335 if (!exec_prefix_set) { 336 exec_prefix = optarg; 337 exec_prefix_set = true; 338 } 339 } 340 else { 341 required_prefix = true; 342 ++num_required_items; 343 } 344 break; 345 346 // --exec_prefix 347 case 'e': 348 if (optarg != 0) { 349 exec_prefix = optarg; 350 exec_prefix_set = true; 351 } 352 else { 353 required_exec_prefix = true; 354 ++num_required_items; 355 } 356 break; 357 358 // --configure-options 359 case 'O': 360 required_configure_options = true; 361 ++num_required_items; 362 break; 363 364 // --version 365 case 'V': 366 required_version = true; 367 ++num_required_items; 368 break; 369 370 // --version-major 371 case 'M': 372 required_version_major = true; 373 ++num_required_items; 374 break; 375 376 // --version-minor 377 case 'N': 378 required_version_minor = true; 379 ++num_required_items; 380 break; 381 382 // --version-revision 383 case 'R': 384 required_version_revision = true; 385 ++num_required_items; 386 break; 387 388 // --version-beta 389 case 'B': 390 required_version_beta = true; 391 ++num_required_items; 392 break; 393 394 // --banner 395 case 'E': 396 required_banner = true; 397 ++num_required_items; 398 break; 399 400 // --coefficients 401 case 'n': 402 required_coefficients = true; 403 ++num_required_items; 404 break; 405 406 // --includedir 407 case 'i': 408 required_includedir = true; 409 ++num_required_items; 410 break; 411 412 // --bindir 413 case 'b': 414 required_bindir = true; 415 ++num_required_items; 416 break; 417 418 // --libdir 419 case 'l': 420 required_libdir = true; 421 ++num_required_items; 422 break; 423 424 // --cppflags 425 case 'P': 426 required_cppflags = true; 427 ++num_required_items; 428 break; 429 430 // --cflags 431 case 'C': 432 required_cflags = true; 433 ++num_required_items; 434 break; 435 436 // --cxxflags 437 case 'X': 438 required_cxxflags = true; 439 ++num_required_items; 440 break; 441 442 // --ldflags 443 case 'D': 444 required_ldflags = true; 445 ++num_required_items; 446 break; 447 448 // --license 449 case 'g': 450 required_license = true; 451 ++num_required_items; 452 break; 453 454 // --copying 455 case 'c': 456 required_copying = true; 457 ++num_required_items; 458 break; 459 460 // --bugs 461 case 'u': 462 required_bugs = true; 463 ++num_required_items; 464 break; 465 466 // --credits 467 case 'r': 468 required_credits = true; 469 ++num_required_items; 470 break; 471 472 default: 473 abort(); 474 } 475 } 476 477 if (argc != optind) 478 // We have a spurious argument. 479 fatal("no arguments besides options are accepted"); 480 481 if (required_application && required_library) 482 fatal("the --application and --library are mutually exclusive"); 483 484 if (!required_application && !required_library) 485 required_application = true; 486 487 if (required_format == NO_FORMAT) 488 required_format = PLAIN; 489 490 if (required_interface == NO_INTERFACE) 491 required_interface = CXX; 492} 493 494void 495portray_name(const char* name) { 496 const char* variable_prefix = "PPL_"; 497 switch (required_format) { 498 case PLAIN: 499 if (num_required_items > 1) 500 std::cout << variable_prefix << name << ": "; 501 break; 502 case MAKEFILE: 503 std::cout << variable_prefix << name << '='; 504 break; 505 case SH: 506 std::cout << "export " << variable_prefix << name << '='; 507 break; 508 case CSH: 509 std::cout << "setenv " << variable_prefix << name << ' '; 510 break; 511 default: 512 internal_error(); 513 } 514} 515 516void 517portray(const char* const array[]) { 518 for (unsigned i = 0; array[i] != 0; ++i) 519 std::cout << array[i] << std::endl; 520} 521 522void 523portray(const char* string) { 524 std::cout << string; 525} 526 527void 528portray(long n) { 529 std::cout << n; 530} 531 532void 533portray(const char* name, const char* const array[]) { 534 portray_name(name); 535 portray(array); 536 std::cout << std::endl; 537} 538 539void 540portray(const char* name, const char* string) { 541 portray_name(name); 542 portray(string); 543 std::cout << std::endl; 544} 545 546void 547portray(const char* name, std::string s) { 548 portray(name, s.c_str()); 549} 550 551void 552portray(const char* name, long n) { 553 portray_name(name); 554 portray(n); 555 std::cout << std::endl; 556} 557 558void 559replace(std::string& s, 560 const std::string& pattern, const std::string& replacement) { 561 std::string::size_type pos = 0; 562 while (true) { 563 pos = s.find(pattern, pos); 564 if (pos == std::string::npos) 565 break; 566 s.replace(pos, pattern.size(), replacement); 567 pos += replacement.length(); 568 } 569} 570 571void 572replace_prefixes(std::string& s) { 573 static const std::string prefix_reference = "${prefix}"; 574 static const std::string exec_prefix_reference = "${exec_prefix}"; 575 replace(s, prefix_reference, prefix); 576 replace(s, exec_prefix_reference, exec_prefix); 577} 578 579void 580portray_with_prefixes(const char* name, std::string s) { 581 replace_prefixes(s); 582 portray(name, s); 583} 584 585} // namespace 586 587int 588main(int argc, char* argv[]) try { 589 program_name = argv[0]; 590 591 if (strcmp(PPL_VERSION, PPL::version()) != 0) 592 fatal("was compiled with PPL version %s, but linked with version %s", 593 PPL_VERSION, PPL::version()); 594 595 // Initialize prefixes. 596 prefix = "@prefix@"; 597 exec_prefix = "@exec_prefix@"; 598 replace_prefixes(prefix); 599 replace_prefixes(exec_prefix); 600 601 // Process command line options. 602 process_options(argc, argv); 603 604 if (required_prefix) 605 portray("PREFIX", prefix); 606 607 if (required_exec_prefix) 608 portray("EXEC_PREFIX", exec_prefix); 609 610 if (required_configure_options) 611 portray("CONFIGURE_OPTIONS", PPL_CONFIGURE_OPTIONS); 612 613 if (required_version) 614 portray("VERSION", PPL_VERSION); 615 616 if (required_version_major) 617 portray("VERSION_MAJOR", static_cast<long>(PPL_VERSION_MAJOR)); 618 619 if (required_version_minor) 620 portray("VERSION_MINOR", static_cast<long>(PPL_VERSION_MINOR)); 621 622 if (required_version_revision) 623 portray("VERSION_REVISION", static_cast<long>(PPL_VERSION_REVISION)); 624 625 if (required_version_beta) 626 portray("VERSION_BETA", static_cast<long>(PPL_VERSION_BETA)); 627 628 if (required_banner) 629 portray("BANNER", PPL::banner()); 630 631 if (required_coefficients) 632 portray("COEFFICIENTS", "@coefficient_mnemonic@"); 633 634 if (required_includedir) 635 portray_with_prefixes("INCLUDEDIR", "@includedir@"); 636 637 if (required_bindir) 638 portray_with_prefixes("BINDIR", "@bindir@"); 639 640 if (required_libdir) 641 portray_with_prefixes("LIBDIR", "@libdir@"); 642 643 if (required_cppflags) { 644 if (required_application) { 645 std::string cppflags = "@CPPFLAGS@"; 646 std::string s = "@includedir@"; 647 replace_prefixes(s); 648 // `/usr/include' is the standard include directory: 649 // thus it needs not be specified. 650 if (s == "/usr/include") 651 s = cppflags; 652 else { 653 s = "-I" + s; 654 // Avoid duplicating the -I options. 655 if (cppflags.find(s) != std::string::npos) 656 s = ""; 657 if (s.length() > 0 && strlen("@CPPFLAGS@") > 0) 658 s += ' '; 659 s += "@CPPFLAGS@"; 660 } 661 if (s.length() > 0 && strlen("@extra_includes@") > 0) 662 s += ' '; 663 s += "@extra_includes@"; 664 portray("CPPFLAGS", s); 665 } 666 else 667 portray("CPPFLAGS", "@CPPFLAGS@"); 668 } 669 670 if (required_cflags) 671 portray("CFLAGS", "@CFLAGS@"); 672 673 if (required_cxxflags) 674 portray("CXXFLAGS", "@CXXFLAGS@"); 675 676 if (required_ldflags) { 677 std::string s = "@libdir@"; 678 replace_prefixes(s); 679 const std::string ldflags = "@LDFLAGS@"; 680 // `/usr/lib' is the standard library directory: 681 // thus it needs not be specified. 682 if (s == "/usr/lib") 683 s = ldflags; 684 else { 685 s = "-L" + s; 686 // Avoid duplicating the -L options. 687 if (ldflags.find(s) != std::string::npos) 688 s = ""; 689 if (s.length() > 0 && ldflags.length() > 0) 690 s += ' '; 691 s += ldflags; 692 } 693 if (required_library) { 694 if (s.length() > 0 && strlen("@extra_libraries@") > 0) 695 s += ' '; 696 s += "@extra_libraries@"; 697 } 698 else { 699 assert(required_application); 700 if (s.length() > 0) 701 s += ' '; 702 s += "-lppl"; 703 if (required_interface == C) 704 s += " -lppl_c"; 705 s += " -lgmpxx -lgmp"; 706 } 707 portray("LDFLAGS", s); 708 } 709 710 if (required_license) 711 portray("LICENSE", PPL_LICENSE); 712 713 if (required_copying) 714 portray("COPYING", COPYING_array); 715 716 if (required_bugs) 717 portray("BUGS", BUGS_array); 718 719 if (required_credits) 720 portray("CREDITS", CREDITS_array); 721 722 return 0; 723} 724catch (const std::bad_alloc&) { 725 fatal("out of memory"); 726 exit(1); 727} 728catch (const std::overflow_error& e) { 729 fatal("arithmetic overflow (%s)", e.what()); 730 exit(1); 731} 732catch (...) { 733 internal_error(); 734} 735