├── configure.exe ├── qconf.qc ├── src ├── configexe │ ├── README.txt │ ├── configexe_stub.exe │ ├── configexe.pro │ ├── embed.h │ ├── embed.c │ └── configexe.c ├── qconf.qrc ├── stringhelp.h ├── stringhelp.cpp └── qconf.cpp ├── examples ├── sample.qc ├── samplecustom.qc ├── samplelib.qc └── sampledeps.qc ├── .gitignore ├── conf ├── conf4.pro ├── conf.pro ├── conf4.h ├── conf.cpp └── conf4.cpp ├── AUTHORS ├── .clang-format ├── package.sh ├── modules └── qt41.qcm ├── TODO ├── qconf.pro ├── README.md ├── COPYING └── configure /configure.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/psi-im/qconf/HEAD/configure.exe -------------------------------------------------------------------------------- /qconf.qc: -------------------------------------------------------------------------------- 1 | 2 | QConf 3 | qconf.pro 4 | 5 | 6 | -------------------------------------------------------------------------------- /src/configexe/README.txt: -------------------------------------------------------------------------------- 1 | 1. Install mingw32 2 | 2. gcc embed.c configexe.c -static-libgcc -o configexe_stub.exe -------------------------------------------------------------------------------- /src/configexe/configexe_stub.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/psi-im/qconf/HEAD/src/configexe/configexe_stub.exe -------------------------------------------------------------------------------- /examples/sample.qc: -------------------------------------------------------------------------------- 1 | 2 | Sample Application 3 | sample.pro 4 | 5 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | qconf 2 | qconf.exe 3 | qconf.pro.user* 4 | Makefile 5 | conf.log 6 | conf.pri 7 | *.o 8 | qrc_*.cpp 9 | .qmake.stash 10 | 11 | -------------------------------------------------------------------------------- /examples/samplecustom.qc: -------------------------------------------------------------------------------- 1 | 2 | Totally Custom Sample 3 | sample.pro 4 | 5 | 6 | -------------------------------------------------------------------------------- /src/qconf.qrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | configexe/configexe_stub.exe 5 | 6 | 7 | -------------------------------------------------------------------------------- /examples/samplelib.qc: -------------------------------------------------------------------------------- 1 | 2 | Sample Library 3 | sample.pro 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /examples/sampledeps.qc: -------------------------------------------------------------------------------- 1 | 2 | Sample Application 3 | sample.pro 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /conf/conf4.pro: -------------------------------------------------------------------------------- 1 | CONFIG += console 2 | CONFIG -= app_bundle 3 | QT -= gui 4 | TARGET = conf 5 | DESTDIR = $$PWD 6 | 7 | HEADERS += conf4.h 8 | SOURCES += conf4.cpp 9 | 10 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | Original developer: 2 | Justin Karneges 3 | 4 | Improvements and maintenance: 5 | Sergey Ilinykh 6 | Ivan Romanov 7 | Boris Pek 8 | -------------------------------------------------------------------------------- /src/configexe/configexe.pro: -------------------------------------------------------------------------------- 1 | CONFIG += console 2 | CONFIG -= qt app_bundle 3 | TARGET = configexe_stub 4 | 5 | CONFIG += release 6 | 7 | *win32-g++*:QMAKE_LFLAGS += -static-libgcc 8 | 9 | HEADERS += \ 10 | embed.h 11 | 12 | SOURCES += \ 13 | embed.c \ 14 | configexe.c 15 | -------------------------------------------------------------------------------- /.clang-format: -------------------------------------------------------------------------------- 1 | BasedOnStyle: WebKit 2 | BreakConstructorInitializers: AfterColon 3 | PointerAlignment: Right 4 | AlignAfterOpenBracket: Align 5 | AlignConsecutiveAssignments: true 6 | AlignConsecutiveDeclarations: true 7 | AlignTrailingComments: true 8 | ColumnLimit: 120 9 | CompactNamespaces: true 10 | -------------------------------------------------------------------------------- /conf/conf.pro: -------------------------------------------------------------------------------- 1 | TEMPLATE = app 2 | CONFIG += qt x11 thread console 3 | TARGET = conf 4 | 5 | DEFINES += X11_INC='"$$QMAKE_INCDIR_X11"' 6 | DEFINES += X11_LIBDIR='"$$QMAKE_LIBDIR_X11"' 7 | DEFINES += X11_LIB='"$$QMAKE_LIBS_X11"' 8 | DEFINES += CC='"$$QMAKE_CC"' 9 | DEFINES += CXX='"$$QMAKE_CXX"' 10 | 11 | SOURCES += conf.cpp 12 | -------------------------------------------------------------------------------- /package.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | 4 | if [ $# -lt 1 ]; then 5 | echo "usage: $0 [version]" 6 | exit 1 7 | fi 8 | 9 | VERSION=$1 10 | 11 | mkdir -p build/qconf-$VERSION 12 | cp -a AUTHORS COPYING README.md TODO conf configure configure.exe examples modules qconf.pro qconf.qc src build/qconf-$VERSION 13 | cd build 14 | tar Jcvf qconf-$VERSION.tar.xz qconf-$VERSION 15 | 16 | echo; echo Packed $(pwd)/qconf-$VERSION.tar.xz 17 | -------------------------------------------------------------------------------- /src/configexe/embed.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2009 Justin Karneges 3 | 4 | This file is free software; unlimited permission is given to copy and/or 5 | distribute it, with or without modifications, as long as this notice is 6 | preserved. 7 | */ 8 | 9 | #ifndef EMBED_H 10 | #define EMBED_H 11 | 12 | unsigned int read32(const unsigned char *in); 13 | 14 | int embed_get_data(const char *argv0, unsigned char **ret_data, unsigned int *ret_size); 15 | 16 | #endif 17 | -------------------------------------------------------------------------------- /modules/qt41.qcm: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2004-2008 Justin Karneges 3 | 4 | This file is free software; unlimited permission is given to copy and/or 5 | distribute it, with or without modifications, as long as this notice is 6 | preserved. 7 | 8 | -----BEGIN QCMOD----- 9 | name: Qt >= 4.1 10 | -----END QCMOD----- 11 | */ 12 | class qc_qt41 : public ConfObj 13 | { 14 | public: 15 | qc_qt41(Conf *c) : ConfObj(c) {} 16 | QString name() const { return "Qt >= 4.1"; } 17 | QString shortname() const { return "qt41"; } 18 | bool exec() 19 | { 20 | return(QT_VERSION >= 0x040100); 21 | } 22 | }; 23 | -------------------------------------------------------------------------------- /TODO: -------------------------------------------------------------------------------- 1 | Store last-used configure arguments in a config.status file. 2 | Don't generate conf.log, put that information in --verbose. 3 | make it possible to use relative paths as input? 4 | 5 | QConf can be considered complete. There are some todo items in this file, 6 | but they are not vital. I've added some rationale text for each one to 7 | explain why. 8 | 9 | - turn .qc file into qmake-style format instead of xml? 10 | 11 | XML is human-readable and nice for application data interchange, but it 12 | isn't very nice to have to write by yourself. I'm using it only because 13 | I didn't want to write a parser. I generally hate it when applications 14 | require manual XML editing (I'm looking at you jabberd), and here I am 15 | committing the same offense. 16 | 17 | Fortunately, the XML files are usually only a handful of lines, and they 18 | work well enough ("if it ain't broke..."). Even so, I think it is worth 19 | looking into supporting an easy-to-write, flat-text format like what is 20 | used for qmake. 21 | -------------------------------------------------------------------------------- /src/stringhelp.h: -------------------------------------------------------------------------------- 1 | /* 2 | * stringhelp.h - string wrapping 3 | * Copyright (C) 2003-2005 Justin Karneges 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU General Public License 7 | * as published by the Free Software Foundation; either version 2 8 | * of the License, or (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this library; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 18 | */ 19 | 20 | #ifndef STRINGHELP_H 21 | #define STRINGHELP_H 22 | 23 | #include 24 | 25 | QStringList wrapString(const QString &str, int wid); 26 | 27 | #endif 28 | -------------------------------------------------------------------------------- /qconf.pro: -------------------------------------------------------------------------------- 1 | QT -= gui 2 | QT += xml 3 | CONFIG += console 4 | CONFIG -= app_bundle 5 | DESTDIR = $$PWD 6 | 7 | HEADERS += src/stringhelp.h 8 | SOURCES += src/stringhelp.cpp src/qconf.cpp 9 | 10 | OTHER_FILES += conf/* 11 | 12 | exists($$OUT_PWD/conf.pri) { 13 | include($$OUT_PWD/conf.pri) 14 | } 15 | 16 | isEmpty(CXXFLAGS) { 17 | CXXFLAGS=$$(CXXFLAGS) 18 | } 19 | 20 | !isEmpty(CXXFLAGS) { 21 | QMAKE_CXXFLAGS = $$CXXFLAGS 22 | QMAKE_CXXFLAGS_DEBUG = $$CXXFLAGS 23 | QMAKE_CXXFLAGS_RELEASE = $$CXXFLAGS 24 | } 25 | 26 | isEmpty(LDFLAGS) { 27 | LDFLAGS=$$(LDFLAGS) 28 | } 29 | 30 | !isEmpty(LDFLAGS) { 31 | QMAKE_LFLAGS = $$LDFLAGS 32 | } 33 | 34 | !isEmpty(DATADIR) { 35 | contains($$list($$[QT_VERSION]), 4.0.*|4.1.*) { 36 | DEFINES += DATADIR=\"$$DATADIR\" 37 | } else { 38 | DEFINES += DATADIR=\\\"$$DATADIR\\\" 39 | } 40 | } 41 | 42 | RESOURCES += src/qconf.qrc 43 | 44 | # install 45 | # we check for empty BINDIR here in case we're debugging with configexe on unix 46 | !isEmpty(BINDIR):!isEmpty(DATADIR) { 47 | #CONFIG += no_fixpath 48 | target.path = $$BINDIR 49 | INSTALLS += target 50 | libfiles.path = $$DATADIR/qconf 51 | libfiles.files = $$IN_PWD/conf $$IN_PWD/modules 52 | INSTALLS += libfiles 53 | } 54 | -------------------------------------------------------------------------------- /src/stringhelp.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * stringhelp.cpp - string wrapping 3 | * Copyright (C) 2003-2005 Justin Karneges 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU General Public License 7 | * as published by the Free Software Foundation; either version 2 8 | * of the License, or (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this library; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 18 | * 19 | */ 20 | 21 | #include "stringhelp.h" 22 | 23 | static QString getNext(QString *str) 24 | { 25 | if (str->isEmpty()) 26 | return QString(); 27 | 28 | // are we in space? 29 | int n = 0; 30 | if (str->at(n).isSpace()) { 31 | // get out of it 32 | while (n < (int)str->length() && str->at(n).isSpace()) 33 | ++n; 34 | if (n == (int)str->length()) 35 | return QString(); 36 | } 37 | // find end or next space 38 | while (n < (int)str->length() && !str->at(n).isSpace()) 39 | ++n; 40 | QString result = str->mid(0, n); 41 | *str = str->mid(n); 42 | return result; 43 | } 44 | 45 | // wraps a string against a fixed width 46 | QStringList wrapString(const QString &str, int wid) 47 | { 48 | QStringList lines; 49 | QString cur; 50 | QString tmp = str; 51 | bool firstword = true; 52 | // printf("parsing: [%s]\n", qPrintable(tmp)); 53 | while (1) { 54 | QString word = getNext(&tmp); 55 | if (word.isNull()) { 56 | lines += cur; 57 | break; 58 | } 59 | // printf("word:[%s]\n", qPrintable(word)); 60 | if (!cur.isEmpty()) { 61 | if ((int)cur.length() + (int)word.length() > wid) { 62 | lines += cur; 63 | cur = ""; 64 | } 65 | } 66 | if (cur.isEmpty() && !firstword) { 67 | // trim the whitespace in front 68 | for (int n = 0; n < (int)word.length(); ++n) { 69 | if (!word.at(n).isSpace()) { 70 | if (n > 0) 71 | word = word.mid(n); 72 | break; 73 | } 74 | } 75 | } 76 | cur += word; 77 | firstword = false; 78 | } 79 | return lines; 80 | } 81 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | QConf v2.4 2 | ========== 3 | 4 | QConf allows you to have a nice configure script for your qmake-based project. It is intended for developers who don't need (or want) to use the more complex GNU autotools. QConf also generates a configure.exe program for use on Windows. 5 | 6 | Developers 7 | ---------- 8 | 9 | See [AUTHORS](https://github.com/psi-plus/qconf/blob/master/AUTHORS) file. 10 | 11 | Installation 12 | ------------ 13 | 14 | ```sh 15 | ./configure 16 | make 17 | make install 18 | ``` 19 | 20 | Usage 21 | ----- 22 | 23 | First, create a project.qc file. It is in an XML format: 24 | 25 | ```xml 26 | 27 | MyProject 28 | project.pro 29 | 30 | ``` 31 | 32 | Then, run qconf on your file: 33 | 34 | ```sh 35 | qconf project.qc 36 | ``` 37 | 38 | Assuming all goes well, this will output `configure` and `configure.exe` programs. Simply copy these files into your application package. Make sure to `include(conf.pri)` in your project.pro file. 39 | 40 | Tip: If qconf is launched with no arguments, it will use the first .qc file it can find in the current directory. If there is no .qc file, then it will look for a .pro file, and create a .qc for you based on it. 41 | 42 | The Configure Programs 43 | ---------------------- 44 | 45 | Once the configure programs have been created, they are immediately usable. The programs perform the following tasks: 46 | 47 | 1. Check for a proper Qt build environment. This is done by compiling the `conf` program, which ensures that the Qt library, qmake, and necessary compiler tools are present and functioning. 48 | 49 | 2. `conf` is launched, which does any needed dependency checking and creates a suitable `conf.pri`. This operation also ensures that not only can Qt-based programs be successfully built, but launched as well. 50 | 51 | 3. qmake is invoked on the project's .pro file. 52 | 53 | Assuming configuration was a success, a `Makefile` should be generated and the user can now run the make tool (e.g. `make`). 54 | 55 | The script does not touch any of your project files. The only output is a `conf.pri` file. It is up to you to actually include `conf.pri` in your .pro file. 56 | 57 | Tip: Passing the `--verbose` option to configure can aid in diagnosing configuration problems. 58 | 59 | Q & A 60 | ----- 61 | 62 | Q: How do I specify dependencies? 63 | A: List them in your .qc file using the `` element. Follow sampledeps.qc for a hint. 64 | 65 | Q: My dependency is not supported! 66 | A: You will need to make it. Look in the `modules` folder to see how it is done. If you find that you need to make a lot of these, perhaps you should consider GNU autotools or CMake. 67 | 68 | Q: How does qconf find modules? 69 | A: Modules are found in the `modules` subdirectory within the configured libdir (default is `/usr/local/share/qconf`). Additional directories can be specified using the `` element. For instance: 70 | 71 | ```xml 72 | qcm 73 | ``` 74 | 75 | The above element would cause qconf to look for modules in the relative directory `qcm`. This is useful if you want to bundle modules within your application distribution. 76 | 77 | Q: How do I perform custom processing or add project-specific arguments? 78 | A: The recommended way of doing this is to create an extra.qcm file that does the processing you need, and then just add it to your .qc file like any normal dependency. Implement `checkString()` in your module to return an empty QString if you want to suppress output. 79 | 80 | Q: How can I install more than just the binary with 'make install'? 81 | A: You need to specify the extra files using the qmake `INSTALLS` variable (see qmake docs for details). 82 | 83 | Q: What environment variables are available? 84 | A: Main variables: `PREFIX`, `BINDIR`, `LIBDIR`, `QTDIR`. All other variables are written as `QC_FOO`, where `FOO` is the option name in all caps. Boolean variables are set to `Y` when flagged. 85 | -------------------------------------------------------------------------------- /conf/conf4.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2004-2008 Justin Karneges 3 | 4 | This file is free software; unlimited permission is given to copy and/or 5 | distribute it, with or without modifications, as long as this notice is 6 | preserved. 7 | */ 8 | 9 | #ifndef QC_CONF4_H 10 | #define QC_CONF4_H 11 | 12 | #include 13 | 14 | class Conf; 15 | 16 | enum VersionMode { VersionMin, VersionExact, VersionMax, VersionAny }; 17 | 18 | // ConfObj 19 | // 20 | // Subclass ConfObj to create a new configuration module. 21 | class ConfObj { 22 | public: 23 | Conf *conf; 24 | bool required; 25 | bool disabled; 26 | bool success; 27 | 28 | ConfObj(Conf *c); 29 | virtual ~ConfObj(); 30 | 31 | // long or descriptive name of what is being checked/performed 32 | // example: "KDE >= 3.3" 33 | virtual QString name() const = 0; 34 | 35 | // short name 36 | // example: "kde" 37 | virtual QString shortname() const = 0; 38 | 39 | // string to display during check 40 | // default: "Checking for [name] ..." 41 | virtual QString checkString() const; 42 | 43 | // string to display after check 44 | // default: "yes" or "no", based on result of exec() 45 | virtual QString resultString() const; 46 | 47 | // this is where the checking code goes 48 | virtual bool exec() = 0; 49 | }; 50 | 51 | // Conf 52 | // 53 | // Interact with this class from your ConfObj to perform detection 54 | // operations and to output configuration parameters. 55 | class Conf { 56 | public: 57 | bool debug_enabled; 58 | QString qmake_path; 59 | QString qmakespec; 60 | QString maketool; 61 | 62 | QString DEFINES; 63 | QStringList INCLUDEPATH; 64 | QStringList LIBS; 65 | QString extra; 66 | 67 | QList list; 68 | QMap vars; 69 | 70 | Conf(); 71 | ~Conf(); 72 | 73 | QString getenv(const QString &var); 74 | QString qvar(const QString &s); 75 | QString normalizePath(const QString &s) const; 76 | QString escapeQmakeVar(const QString &s) const; 77 | inline QString escapePath(const QString &s) /* prepare fs path for qmake file */ 78 | { 79 | return escapeQmakeVar(normalizePath(s)); 80 | } 81 | QString escapedIncludes() const; 82 | QString escapedLibs() const; 83 | 84 | bool exec(); 85 | 86 | void debug(const QString &s); 87 | 88 | QString expandIncludes(const QString &inc); 89 | QString expandLibs(const QString &lib); 90 | 91 | int doCommand(const QString &s, QByteArray *out = 0); 92 | int doCommand(const QString &prog, const QStringList &args, QByteArray *out = 0); 93 | 94 | bool doCompileAndLink(const QString &filedata, const QStringList &incs, const QString &libs, 95 | const QString &proextra, int *retcode = 0); 96 | bool checkHeader(const QString &path, const QString &h); 97 | bool findHeader(const QString &h, const QStringList &ext, QString *inc); 98 | bool checkLibrary(const QString &path, const QString &name); 99 | bool findLibrary(const QString &name, QString *lib); 100 | QString findProgram(const QString &prog); 101 | bool findSimpleLibrary(const QString &incvar, const QString &libvar, const QString &incname, const QString &libname, 102 | QString *incpath, QString *libs); 103 | bool findFooConfig(const QString &path, QString *version, QStringList *incs, QString *libs, QString *otherflags); 104 | bool findPkgConfig(const QString &name, VersionMode mode, const QString &req_version, QString *version, 105 | QStringList *incs, QString *libs, QString *otherflags); 106 | 107 | void addDefine(const QString &str); 108 | void addLib(const QString &str); 109 | void addIncludePath(const QString &str); 110 | void addExtra(const QString &str); 111 | 112 | private: 113 | bool first_debug; 114 | 115 | friend class ConfObj; 116 | void added(ConfObj *o); 117 | }; 118 | 119 | #endif 120 | -------------------------------------------------------------------------------- /src/configexe/embed.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2009 Justin Karneges 3 | 4 | This file is free software; unlimited permission is given to copy and/or 5 | distribute it, with or without modifications, as long as this notice is 6 | preserved. 7 | */ 8 | 9 | #include "embed.h" 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | #if defined(WIN32) || defined(_WIN32) 16 | # define QC_OS_WIN 17 | # include 18 | #endif 19 | 20 | // this hash stuff is total overkill but i was bored 21 | 22 | static const char *BLOCKSIG_ID = "QCONF_CONFIGWIN_BLOCKSIG"; 23 | 24 | static unsigned int calc_hash(const char *in, int len) 25 | { 26 | unsigned int x; 27 | int n; 28 | 29 | x = 0; 30 | for(n = 0; n < len; ++n) 31 | { 32 | x <<= 4; 33 | x ^= (unsigned int)in[n]; 34 | } 35 | return x; 36 | } 37 | 38 | // result should be "QCONF_CONFIGWIN_BLOCKSIG_68b7e7d7" 39 | // 40 | // the basic idea here is that we use this string as a marker for our 41 | // appended data section, but we don't want to include this actual 42 | // string in our code otherwise it could be misinterpretted as the 43 | // marker 44 | static char *blocksig() 45 | { 46 | char *blocksig_data; 47 | int idlen; 48 | unsigned int hash; 49 | char hashstr[9]; 50 | int n; 51 | 52 | idlen = strlen(BLOCKSIG_ID); 53 | hash = calc_hash(BLOCKSIG_ID, idlen); 54 | blocksig_data = (char *)malloc(idlen + 1 + 8 + 1); 55 | memcpy(blocksig_data, BLOCKSIG_ID, idlen); 56 | blocksig_data[idlen] = '_'; 57 | sprintf(hashstr, "%08x", hash); 58 | for(n = 0; n < 8; ++n) 59 | blocksig_data[idlen + 1 + n] = hashstr[n]; 60 | blocksig_data[idlen + 1 + 8] = 0; 61 | 62 | return blocksig_data; 63 | } 64 | 65 | static char *app_file_path(const char *argv0) 66 | { 67 | #ifdef QC_OS_WIN 68 | char module_name[MAX_PATH+1]; 69 | (void)argv0; 70 | GetModuleFileNameA(0, module_name, MAX_PATH); 71 | module_name[MAX_PATH] = 0; 72 | return strdup(module_name); 73 | #else 74 | return strdup(argv0); 75 | #endif 76 | } 77 | 78 | static int find_partial(const char *in, int in_size, const char *sub, int sub_size) 79 | { 80 | int n; 81 | int size; 82 | 83 | for(n = 0; n < in_size; ++n) 84 | { 85 | if(sub_size < in_size - n) 86 | size = sub_size; 87 | else 88 | size = in_size - n; 89 | if(memcmp(in + n, sub, size) == 0) 90 | return n; 91 | } 92 | 93 | return -1; 94 | } 95 | 96 | static int seek_string(FILE *fp, const char *str) 97 | { 98 | char block[8192]; 99 | int str_at; 100 | int str_len; 101 | int size; 102 | int ret; 103 | int pos; 104 | 105 | str_len = strlen(str); 106 | str_at = 0; 107 | pos = ftell(fp); 108 | while(!feof(fp)) 109 | { 110 | size = fread(block, 1, 8192, fp); 111 | if(size < 1) 112 | break; 113 | 114 | ret = find_partial(block, size, str + str_at, str_len - str_at); 115 | if(ret != -1) 116 | { 117 | if(str_at + (size - ret) >= str_len) 118 | { 119 | if(fseek(fp, pos + ret - str_at + str_len, SEEK_SET) != 0) 120 | return 0; 121 | 122 | return 1; 123 | } 124 | else 125 | str_at += (size - ret); 126 | } 127 | 128 | pos += size; 129 | } 130 | 131 | return 0; 132 | } 133 | 134 | unsigned int read32(const unsigned char *in) 135 | { 136 | unsigned int out = in[0]; 137 | out <<= 8; 138 | out += in[1]; 139 | out <<= 8; 140 | out += in[2]; 141 | out <<= 8; 142 | out += in[3]; 143 | return out; 144 | } 145 | 146 | // format is: 147 | // 148 | 149 | static int import_data(const char *argv0, const char *sig, unsigned char **ret_data, unsigned int *ret_size) 150 | { 151 | char *fname; 152 | FILE *fp; 153 | int ret; 154 | unsigned char buf[4]; 155 | unsigned int size; 156 | unsigned char *data; 157 | 158 | fname = app_file_path(argv0); 159 | if(!fname) 160 | return 0; 161 | fp = fopen(fname, "rb"); 162 | if(!fp) 163 | return 0; 164 | if(!seek_string(fp, sig)) 165 | return 0; 166 | ret = fread(buf, 4, 1, fp); 167 | if(ret < 1) 168 | return 0; 169 | size = read32(buf); 170 | data = (unsigned char *)malloc(size); 171 | if(!data) 172 | return 0; 173 | ret = fread(data, size, 1, fp); 174 | if(ret < 1) 175 | { 176 | free(data); 177 | return 0; 178 | } 179 | fclose(fp); 180 | 181 | *ret_data = data; 182 | *ret_size = size; 183 | return 1; 184 | } 185 | 186 | int embed_get_data(const char *argv0, unsigned char **ret_data, unsigned int *ret_size) 187 | { 188 | char *sig; 189 | int ret; 190 | 191 | sig = blocksig(); 192 | //printf("%s\n", sig); 193 | ret = import_data(argv0, sig, ret_data, ret_size); 194 | free(sig); 195 | 196 | return ret; 197 | } 198 | -------------------------------------------------------------------------------- /conf/conf.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2003-2008 Justin Karneges 3 | 4 | This file is free software; unlimited permission is given to copy and/or 5 | distribute it, with or without modifications, as long as this notice is 6 | preserved. 7 | */ 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | class MocTestObject : public QObject { 21 | Q_OBJECT 22 | public: 23 | MocTestObject() {} 24 | }; 25 | 26 | class Conf; 27 | 28 | class ConfObj { 29 | public: 30 | ConfObj(Conf *c); 31 | virtual ~ConfObj(); 32 | 33 | virtual QString name() const = 0; 34 | virtual QString shortname() const = 0; 35 | virtual QString checkString() const; 36 | virtual QString resultString() const; 37 | virtual bool exec() = 0; 38 | 39 | Conf *conf; 40 | bool required; 41 | bool disabled; 42 | }; 43 | 44 | typedef QPtrList ConfObjList; 45 | typedef QPtrListIterator ConfObjListIt; 46 | 47 | class Conf { 48 | public: 49 | Conf() : vars(17) 50 | { 51 | list.setAutoDelete(true); 52 | vars.setAutoDelete(true); 53 | 54 | vars.insert("QMAKE_INCDIR_X11", new QString(X11_INC)); 55 | vars.insert("QMAKE_LIBDIR_X11", new QString(X11_LIBDIR)); 56 | vars.insert("QMAKE_LIBS_X11", new QString(X11_LIB)); 57 | vars.insert("QMAKE_CC", new QString(CC)); 58 | vars.insert("QMAKE_CXX", new QString(CXX)); 59 | 60 | do_debug = false; 61 | done_debug = false; 62 | } 63 | 64 | ~Conf() {} 65 | 66 | void added(ConfObj *o) { list.append(o); } 67 | 68 | QString getenv(const QString &var) 69 | { 70 | char *p = ::getenv(var.latin1()); 71 | if (!p) 72 | return QString::null; 73 | return QString(p); 74 | } 75 | 76 | void debug(const QString &s) 77 | { 78 | if (do_debug) { 79 | if (!done_debug) 80 | printf("\n"); 81 | done_debug = true; 82 | printf(" * %s\n", s.latin1()); 83 | } 84 | } 85 | 86 | bool exec() 87 | { 88 | if (getenv("QC_VERBOSE") == "Y") 89 | do_debug = true; 90 | 91 | ConfObjListIt it(list); 92 | for (ConfObj *o; (o = it.current()); ++it) { 93 | // if this was a disabled-by-default option, check if it was enabled 94 | if (o->disabled) { 95 | QString v = QString("QC_ENABLE_") + o->shortname(); 96 | if (getenv(v) != "Y") 97 | continue; 98 | } 99 | // and the opposite? 100 | else { 101 | QString v = QString("QC_DISABLE_") + o->shortname(); 102 | if (getenv(v) == "Y") 103 | continue; 104 | } 105 | 106 | QString check = o->checkString(); 107 | if (check.isEmpty()) 108 | check = QString("Checking for %1 ...").arg(o->name()); 109 | printf("%s", check.latin1()); 110 | fflush(stdout); 111 | 112 | done_debug = false; 113 | bool ok = o->exec(); 114 | 115 | QString result = o->resultString(); 116 | if (result.isEmpty()) { 117 | if (ok) 118 | result = "yes"; 119 | else 120 | result = "no"; 121 | } 122 | if (done_debug) 123 | printf(" -> %s\n", result.latin1()); 124 | else 125 | printf(" %s\n", result.latin1()); 126 | 127 | if (!ok && o->required) { 128 | printf("\nError: need %s!\n", o->name().latin1()); 129 | return false; 130 | } 131 | } 132 | return true; 133 | } 134 | 135 | const QString &qvar(const QString &s) 136 | { 137 | QString *p = vars.find(s); 138 | if (p) 139 | return *p; 140 | else 141 | return blank; 142 | } 143 | 144 | QString expandIncludes(const QString &inc) { return QString("-I") + inc; } 145 | 146 | QString expandLibs(const QString &lib) { return QString("-L") + lib; } 147 | 148 | int doCommand(const QString &s) 149 | { 150 | debug(QString("[%1]").arg(s)); 151 | QString fullcmd; 152 | if (do_debug) 153 | fullcmd = s; 154 | else 155 | fullcmd = s + " 1>/dev/null 2>/dev/null"; 156 | int r = system(fullcmd.latin1()); 157 | debug(QString("returned: %1").arg(r)); 158 | return r; 159 | } 160 | 161 | bool doCompileAndLink(const QString &filedata, const QString &flags, int *retcode = 0) 162 | { 163 | QDir dir("."); 164 | QString fname = "atest.c"; 165 | QString out = "atest"; 166 | QFile f(fname); 167 | QCString cs = filedata.latin1(); 168 | if (!f.open(IO_WriteOnly | IO_Truncate)) { 169 | debug("unable to open atest.c for writing"); 170 | return false; 171 | } 172 | if (f.writeBlock(cs.data(), cs.length()) == -1) { 173 | debug("error writing to atest.c"); 174 | return false; 175 | } 176 | f.close(); 177 | 178 | debug(QString("Wrote atest.c:\n%1").arg(filedata)); 179 | 180 | QString str = qvar("QMAKE_CXX") + ' ' + fname + " -o " + out; 181 | if (!flags.isEmpty()) { 182 | str += ' '; 183 | str += flags; 184 | } 185 | 186 | int r = doCommand(str); 187 | if (r == 0 && retcode) 188 | *retcode = doCommand(QString("./") + out); 189 | dir.remove(fname); 190 | dir.remove(out); 191 | if (r != 0) 192 | return false; 193 | return true; 194 | } 195 | 196 | bool checkHeader(const QString &path, const QString &h) 197 | { 198 | QFileInfo fi(path + '/' + h); 199 | if (fi.exists()) 200 | return true; 201 | return false; 202 | } 203 | 204 | bool findHeader(const QString &h, const QStringList &ext, QString *inc) 205 | { 206 | if (checkHeader("/usr/include", h)) { 207 | *inc = ""; 208 | return true; 209 | } 210 | QStringList dirs; 211 | dirs += "/usr/local/include"; 212 | dirs += ext; 213 | for (QStringList::ConstIterator it = dirs.begin(); it != dirs.end(); ++it) { 214 | if (checkHeader(*it, h)) { 215 | *inc = *it; 216 | return true; 217 | } 218 | } 219 | return false; 220 | } 221 | 222 | bool checkLibrary(const QString &path, const QString &name) 223 | { 224 | QString str = "int main()\n" 225 | "{\n" 226 | " return 0;\n" 227 | "}\n"; 228 | 229 | QString extra; 230 | if (!path.isEmpty()) 231 | extra += QString("-L") + path + ' '; 232 | extra += QString("-l") + name; 233 | if (!doCompileAndLink(str, extra)) 234 | return false; 235 | return true; 236 | } 237 | 238 | bool findLibrary(const QString &name, QString *lib) 239 | { 240 | if (checkLibrary("", name)) { 241 | *lib = ""; 242 | return true; 243 | } 244 | if (checkLibrary("/usr/local/lib", name)) { 245 | *lib = "/usr/local/lib"; 246 | return true; 247 | } 248 | return false; 249 | } 250 | 251 | void addDefine(const QString &str) 252 | { 253 | if (DEFINES.isEmpty()) 254 | DEFINES = str; 255 | else 256 | DEFINES += QString(" ") + str; 257 | debug(QString("DEFINES += %1").arg(str)); 258 | } 259 | 260 | void addLib(const QString &str) 261 | { 262 | if (LIBS.isEmpty()) 263 | LIBS = str; 264 | else 265 | LIBS += QString(" ") + str; 266 | debug(QString("LIBS += %1").arg(str)); 267 | } 268 | 269 | void addIncludePath(const QString &str) 270 | { 271 | if (INCLUDEPATH.isEmpty()) 272 | INCLUDEPATH = str; 273 | else 274 | INCLUDEPATH += QString(" ") + str; 275 | debug(QString("INCLUDEPATH += %1").arg(str)); 276 | } 277 | 278 | void addExtra(const QString &str) 279 | { 280 | extra += str + '\n'; 281 | debug(QString("extra += %1").arg(str)); 282 | } 283 | 284 | QString DEFINES; 285 | QString INCLUDEPATH; 286 | QString LIBS; 287 | QString extra; 288 | 289 | private: 290 | ConfObjList list; 291 | QDict vars; 292 | QString blank; 293 | bool do_debug, done_debug; 294 | }; 295 | 296 | ConfObj::ConfObj(Conf *c) 297 | { 298 | conf = c; 299 | conf->added(this); 300 | required = false; 301 | disabled = false; 302 | } 303 | 304 | ConfObj::~ConfObj() {} 305 | 306 | QString ConfObj::checkString() const { return QString(); } 307 | 308 | QString ConfObj::resultString() const { return QString(); } 309 | 310 | #include "modules.cpp" 311 | 312 | //---------------------------------------------------------------------------- 313 | // main 314 | //---------------------------------------------------------------------------- 315 | int main() 316 | { 317 | Conf * conf = new Conf; 318 | ConfObj *o; 319 | o = 0; 320 | #include "modules_new.cpp" 321 | 322 | printf("ok\n"); 323 | bool success = false; 324 | if (conf->exec()) { 325 | QFile f("conf.pri"); 326 | if (!f.open(IO_WriteOnly | IO_Truncate)) { 327 | printf("Error writing %s\n", f.name().latin1()); 328 | return 1; 329 | } 330 | 331 | QString str; 332 | str += "# qconf\n"; 333 | str += "QT_PATH_PLUGINS = " + QString(qInstallPathPlugins()) + '\n'; 334 | if (!conf->DEFINES.isEmpty()) 335 | str += "DEFINES += " + conf->DEFINES + '\n'; 336 | if (!conf->INCLUDEPATH.isEmpty()) 337 | str += "INCLUDEPATH += " + conf->INCLUDEPATH + '\n'; 338 | if (!conf->LIBS.isEmpty()) 339 | str += "LIBS += " + conf->LIBS + '\n'; 340 | if (!conf->extra.isEmpty()) 341 | str += conf->extra; 342 | str += '\n'; 343 | 344 | char *p = getenv("BINDIR"); 345 | if (p) { 346 | str += QString("target.path = ") + p + '\n'; 347 | str += "INSTALLS += target\n"; 348 | } 349 | 350 | QCString cs = str.latin1(); 351 | f.writeBlock(cs.data(), cs.length()); 352 | f.close(); 353 | success = true; 354 | } 355 | delete conf; 356 | 357 | if (success) 358 | return 0; 359 | else 360 | return 1; 361 | } 362 | 363 | #include "conf.moc" 364 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | 2 | As a special exception, Justin Karneges gives permission to link 3 | this program with the Qt Library (commercial or non-commercial edition), 4 | and distribute the resulting executable, without including the source 5 | code for the Qt library in the source distribution. 6 | 7 | Files generated by qconf (such as 'configure') are not considered to be 8 | a derived work of any of the input files used to create them, even though 9 | the input files might be included verbatim in the generated files. These 10 | generated files can be freely used and distributed and are not bound by 11 | the license terms below. 12 | 13 | 14 | GNU GENERAL PUBLIC LICENSE 15 | Version 2, June 1991 16 | 17 | Copyright (C) 1989, 1991 Free Software Foundation, Inc. 18 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 19 | Everyone is permitted to copy and distribute verbatim copies 20 | of this license document, but changing it is not allowed. 21 | 22 | Preamble 23 | 24 | The licenses for most software are designed to take away your 25 | freedom to share and change it. By contrast, the GNU General Public 26 | License is intended to guarantee your freedom to share and change free 27 | software--to make sure the software is free for all its users. This 28 | General Public License applies to most of the Free Software 29 | Foundation's software and to any other program whose authors commit to 30 | using it. (Some other Free Software Foundation software is covered by 31 | the GNU Library General Public License instead.) You can apply it to 32 | your programs, too. 33 | 34 | When we speak of free software, we are referring to freedom, not 35 | price. Our General Public Licenses are designed to make sure that you 36 | have the freedom to distribute copies of free software (and charge for 37 | this service if you wish), that you receive source code or can get it 38 | if you want it, that you can change the software or use pieces of it 39 | in new free programs; and that you know you can do these things. 40 | 41 | To protect your rights, we need to make restrictions that forbid 42 | anyone to deny you these rights or to ask you to surrender the rights. 43 | These restrictions translate to certain responsibilities for you if you 44 | distribute copies of the software, or if you modify it. 45 | 46 | For example, if you distribute copies of such a program, whether 47 | gratis or for a fee, you must give the recipients all the rights that 48 | you have. You must make sure that they, too, receive or can get the 49 | source code. And you must show them these terms so they know their 50 | rights. 51 | 52 | We protect your rights with two steps: (1) copyright the software, and 53 | (2) offer you this license which gives you legal permission to copy, 54 | distribute and/or modify the software. 55 | 56 | Also, for each author's protection and ours, we want to make certain 57 | that everyone understands that there is no warranty for this free 58 | software. If the software is modified by someone else and passed on, we 59 | want its recipients to know that what they have is not the original, so 60 | that any problems introduced by others will not reflect on the original 61 | authors' reputations. 62 | 63 | Finally, any free program is threatened constantly by software 64 | patents. We wish to avoid the danger that redistributors of a free 65 | program will individually obtain patent licenses, in effect making the 66 | program proprietary. To prevent this, we have made it clear that any 67 | patent must be licensed for everyone's free use or not licensed at all. 68 | 69 | The precise terms and conditions for copying, distribution and 70 | modification follow. 71 | 72 | GNU GENERAL PUBLIC LICENSE 73 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 74 | 75 | 0. This License applies to any program or other work which contains 76 | a notice placed by the copyright holder saying it may be distributed 77 | under the terms of this General Public License. The "Program", below, 78 | refers to any such program or work, and a "work based on the Program" 79 | means either the Program or any derivative work under copyright law: 80 | that is to say, a work containing the Program or a portion of it, 81 | either verbatim or with modifications and/or translated into another 82 | language. (Hereinafter, translation is included without limitation in 83 | the term "modification".) Each licensee is addressed as "you". 84 | 85 | Activities other than copying, distribution and modification are not 86 | covered by this License; they are outside its scope. The act of 87 | running the Program is not restricted, and the output from the Program 88 | is covered only if its contents constitute a work based on the 89 | Program (independent of having been made by running the Program). 90 | Whether that is true depends on what the Program does. 91 | 92 | 1. You may copy and distribute verbatim copies of the Program's 93 | source code as you receive it, in any medium, provided that you 94 | conspicuously and appropriately publish on each copy an appropriate 95 | copyright notice and disclaimer of warranty; keep intact all the 96 | notices that refer to this License and to the absence of any warranty; 97 | and give any other recipients of the Program a copy of this License 98 | along with the Program. 99 | 100 | You may charge a fee for the physical act of transferring a copy, and 101 | you may at your option offer warranty protection in exchange for a fee. 102 | 103 | 2. You may modify your copy or copies of the Program or any portion 104 | of it, thus forming a work based on the Program, and copy and 105 | distribute such modifications or work under the terms of Section 1 106 | above, provided that you also meet all of these conditions: 107 | 108 | a) You must cause the modified files to carry prominent notices 109 | stating that you changed the files and the date of any change. 110 | 111 | b) You must cause any work that you distribute or publish, that in 112 | whole or in part contains or is derived from the Program or any 113 | part thereof, to be licensed as a whole at no charge to all third 114 | parties under the terms of this License. 115 | 116 | c) If the modified program normally reads commands interactively 117 | when run, you must cause it, when started running for such 118 | interactive use in the most ordinary way, to print or display an 119 | announcement including an appropriate copyright notice and a 120 | notice that there is no warranty (or else, saying that you provide 121 | a warranty) and that users may redistribute the program under 122 | these conditions, and telling the user how to view a copy of this 123 | License. (Exception: if the Program itself is interactive but 124 | does not normally print such an announcement, your work based on 125 | the Program is not required to print an announcement.) 126 | 127 | These requirements apply to the modified work as a whole. If 128 | identifiable sections of that work are not derived from the Program, 129 | and can be reasonably considered independent and separate works in 130 | themselves, then this License, and its terms, do not apply to those 131 | sections when you distribute them as separate works. But when you 132 | distribute the same sections as part of a whole which is a work based 133 | on the Program, the distribution of the whole must be on the terms of 134 | this License, whose permissions for other licensees extend to the 135 | entire whole, and thus to each and every part regardless of who wrote it. 136 | 137 | Thus, it is not the intent of this section to claim rights or contest 138 | your rights to work written entirely by you; rather, the intent is to 139 | exercise the right to control the distribution of derivative or 140 | collective works based on the Program. 141 | 142 | In addition, mere aggregation of another work not based on the Program 143 | with the Program (or with a work based on the Program) on a volume of 144 | a storage or distribution medium does not bring the other work under 145 | the scope of this License. 146 | 147 | 3. You may copy and distribute the Program (or a work based on it, 148 | under Section 2) in object code or executable form under the terms of 149 | Sections 1 and 2 above provided that you also do one of the following: 150 | 151 | a) Accompany it with the complete corresponding machine-readable 152 | source code, which must be distributed under the terms of Sections 153 | 1 and 2 above on a medium customarily used for software interchange; or, 154 | 155 | b) Accompany it with a written offer, valid for at least three 156 | years, to give any third party, for a charge no more than your 157 | cost of physically performing source distribution, a complete 158 | machine-readable copy of the corresponding source code, to be 159 | distributed under the terms of Sections 1 and 2 above on a medium 160 | customarily used for software interchange; or, 161 | 162 | c) Accompany it with the information you received as to the offer 163 | to distribute corresponding source code. (This alternative is 164 | allowed only for noncommercial distribution and only if you 165 | received the program in object code or executable form with such 166 | an offer, in accord with Subsection b above.) 167 | 168 | The source code for a work means the preferred form of the work for 169 | making modifications to it. For an executable work, complete source 170 | code means all the source code for all modules it contains, plus any 171 | associated interface definition files, plus the scripts used to 172 | control compilation and installation of the executable. However, as a 173 | special exception, the source code distributed need not include 174 | anything that is normally distributed (in either source or binary 175 | form) with the major components (compiler, kernel, and so on) of the 176 | operating system on which the executable runs, unless that component 177 | itself accompanies the executable. 178 | 179 | If distribution of executable or object code is made by offering 180 | access to copy from a designated place, then offering equivalent 181 | access to copy the source code from the same place counts as 182 | distribution of the source code, even though third parties are not 183 | compelled to copy the source along with the object code. 184 | 185 | 4. You may not copy, modify, sublicense, or distribute the Program 186 | except as expressly provided under this License. Any attempt 187 | otherwise to copy, modify, sublicense or distribute the Program is 188 | void, and will automatically terminate your rights under this License. 189 | However, parties who have received copies, or rights, from you under 190 | this License will not have their licenses terminated so long as such 191 | parties remain in full compliance. 192 | 193 | 5. You are not required to accept this License, since you have not 194 | signed it. However, nothing else grants you permission to modify or 195 | distribute the Program or its derivative works. These actions are 196 | prohibited by law if you do not accept this License. Therefore, by 197 | modifying or distributing the Program (or any work based on the 198 | Program), you indicate your acceptance of this License to do so, and 199 | all its terms and conditions for copying, distributing or modifying 200 | the Program or works based on it. 201 | 202 | 6. Each time you redistribute the Program (or any work based on the 203 | Program), the recipient automatically receives a license from the 204 | original licensor to copy, distribute or modify the Program subject to 205 | these terms and conditions. You may not impose any further 206 | restrictions on the recipients' exercise of the rights granted herein. 207 | You are not responsible for enforcing compliance by third parties to 208 | this License. 209 | 210 | 7. If, as a consequence of a court judgment or allegation of patent 211 | infringement or for any other reason (not limited to patent issues), 212 | conditions are imposed on you (whether by court order, agreement or 213 | otherwise) that contradict the conditions of this License, they do not 214 | excuse you from the conditions of this License. If you cannot 215 | distribute so as to satisfy simultaneously your obligations under this 216 | License and any other pertinent obligations, then as a consequence you 217 | may not distribute the Program at all. For example, if a patent 218 | license would not permit royalty-free redistribution of the Program by 219 | all those who receive copies directly or indirectly through you, then 220 | the only way you could satisfy both it and this License would be to 221 | refrain entirely from distribution of the Program. 222 | 223 | If any portion of this section is held invalid or unenforceable under 224 | any particular circumstance, the balance of the section is intended to 225 | apply and the section as a whole is intended to apply in other 226 | circumstances. 227 | 228 | It is not the purpose of this section to induce you to infringe any 229 | patents or other property right claims or to contest validity of any 230 | such claims; this section has the sole purpose of protecting the 231 | integrity of the free software distribution system, which is 232 | implemented by public license practices. Many people have made 233 | generous contributions to the wide range of software distributed 234 | through that system in reliance on consistent application of that 235 | system; it is up to the author/donor to decide if he or she is willing 236 | to distribute software through any other system and a licensee cannot 237 | impose that choice. 238 | 239 | This section is intended to make thoroughly clear what is believed to 240 | be a consequence of the rest of this License. 241 | 242 | 8. If the distribution and/or use of the Program is restricted in 243 | certain countries either by patents or by copyrighted interfaces, the 244 | original copyright holder who places the Program under this License 245 | may add an explicit geographical distribution limitation excluding 246 | those countries, so that distribution is permitted only in or among 247 | countries not thus excluded. In such case, this License incorporates 248 | the limitation as if written in the body of this License. 249 | 250 | 9. The Free Software Foundation may publish revised and/or new versions 251 | of the General Public License from time to time. Such new versions will 252 | be similar in spirit to the present version, but may differ in detail to 253 | address new problems or concerns. 254 | 255 | Each version is given a distinguishing version number. If the Program 256 | specifies a version number of this License which applies to it and "any 257 | later version", you have the option of following the terms and conditions 258 | either of that version or of any later version published by the Free 259 | Software Foundation. If the Program does not specify a version number of 260 | this License, you may choose any version ever published by the Free Software 261 | Foundation. 262 | 263 | 10. If you wish to incorporate parts of the Program into other free 264 | programs whose distribution conditions are different, write to the author 265 | to ask for permission. For software which is copyrighted by the Free 266 | Software Foundation, write to the Free Software Foundation; we sometimes 267 | make exceptions for this. Our decision will be guided by the two goals 268 | of preserving the free status of all derivatives of our free software and 269 | of promoting the sharing and reuse of software generally. 270 | 271 | NO WARRANTY 272 | 273 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 274 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 275 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 276 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 277 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 278 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 279 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 280 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 281 | REPAIR OR CORRECTION. 282 | 283 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 284 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 285 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 286 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 287 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 288 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 289 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 290 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 291 | POSSIBILITY OF SUCH DAMAGES. 292 | 293 | END OF TERMS AND CONDITIONS 294 | -------------------------------------------------------------------------------- /src/configexe/configexe.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2009 Justin Karneges 3 | 4 | This file is free software; unlimited permission is given to copy and/or 5 | distribute it, with or without modifications, as long as this notice is 6 | preserved. 7 | */ 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | //#include 16 | #include 17 | #include "embed.h" 18 | 19 | #if defined(WIN32) || defined(_WIN32) 20 | # define QC_OS_WIN 21 | #endif 22 | 23 | #ifdef QC_OS_WIN 24 | #include 25 | #endif 26 | 27 | #ifdef QC_OS_WIN 28 | static char *qconftemp_path = "qconftemp"; 29 | static char path_separator = ';'; 30 | #else 31 | static char *qconftemp_path = ".qconftemp"; 32 | static char path_separator = ':'; 33 | #endif 34 | 35 | static int qc_verbose = 0; 36 | static char *ex_qtdir = NULL; 37 | static char *qc_qtselect = NULL; 38 | static char *qtsearchtext="4 or 5"; 39 | 40 | static char *prefix = NULL; 41 | static char *bindir = NULL; 42 | static char *includedir = NULL; 43 | static char *libdir = NULL; 44 | static char *datadir = NULL; 45 | 46 | static int run_buffer_stdout(const char *command, char *out_buf, size_t buf_size); 47 | 48 | enum ArgType 49 | { 50 | ArgValue, 51 | ArgFlag 52 | }; 53 | 54 | typedef struct qcarg 55 | { 56 | char *name; 57 | char *envvar; 58 | int type; 59 | char *val; // we populate this later based on actual passed args 60 | } qcarg_t; 61 | 62 | typedef struct qcfile 63 | { 64 | char *name; 65 | unsigned char *data; 66 | unsigned int size; 67 | } qcfile_t; 68 | 69 | typedef struct qcdata 70 | { 71 | char *usage; 72 | 73 | qcarg_t *args; 74 | int args_count; 75 | 76 | qcfile_t *files; 77 | int files_count; 78 | 79 | char *pro_name; 80 | char *pro_file; 81 | 82 | char *qtinfo; 83 | } qcdata_t; 84 | 85 | static char *alloc_str(const unsigned char *src, int len) 86 | { 87 | char *out; 88 | out = (char *)malloc(len + 1); 89 | memcpy(out, src, len); 90 | out[len] = 0; 91 | return out; 92 | } 93 | 94 | static int index_of(const char *in, char sub) 95 | { 96 | int n; 97 | for(n = 0; in[n]; ++n) 98 | { 99 | if(in[n] == sub) 100 | return n; 101 | } 102 | return -1; 103 | } 104 | 105 | static int index_of_str(const char *in, const char *sub) 106 | { 107 | char *p; 108 | p = strstr(in, sub); 109 | if(p) 110 | return p - in; 111 | else 112 | return -1; 113 | } 114 | 115 | static char *selection_insert(const char *in, int at, int len, const char *sub) 116 | { 117 | int ilen; 118 | int slen; 119 | int newsize; 120 | char *out; 121 | 122 | ilen = strlen(in); 123 | slen = strlen(sub); 124 | newsize = ilen - len + slen; 125 | out = (char *)malloc(newsize + 1); 126 | memcpy(out, in, at); 127 | memcpy(out + at, sub, slen); 128 | memcpy(out + at + slen, in + at + len, ilen - at - len); 129 | out[newsize] = 0; 130 | 131 | return out; 132 | } 133 | 134 | static char *find_replace(const char *in, const char *old, const char *newv) 135 | { 136 | int at; 137 | int olen; 138 | 139 | olen = strlen(old); 140 | at = index_of_str(in, old); 141 | if(at != -1) 142 | return selection_insert(in, at, olen, newv); 143 | else 144 | return strdup(in); 145 | } 146 | 147 | static char *append_str(const char *in, const char *add) 148 | { 149 | return selection_insert(in, strlen(in), 0, add); 150 | } 151 | 152 | // creates new string and frees old 153 | static char *append_free(char *in, const char *add) 154 | { 155 | char *out; 156 | out = append_str(in, add); 157 | free(in); 158 | return out; 159 | } 160 | 161 | // FIXME: handle bad data, don't malloc 0, etc 162 | static qcdata_t *parse_data(unsigned char *data, unsigned int size) 163 | { 164 | unsigned char *p; 165 | qcdata_t *q; 166 | unsigned int len; 167 | int n; 168 | 169 | (void)size; 170 | 171 | q = (qcdata_t *)malloc(sizeof(qcdata_t)); 172 | p = data; 173 | len = read32(p); 174 | p += 4; 175 | q->usage = alloc_str(p, len); 176 | p += len; 177 | 178 | q->args_count = read32(p); 179 | p += 4; 180 | q->args = (qcarg_t *)malloc(sizeof(qcarg_t) * q->args_count); 181 | for(n = 0; n < q->args_count; ++n) 182 | { 183 | len = read32(p); 184 | p += 4; 185 | q->args[n].name = alloc_str(p, len); 186 | p += len; 187 | 188 | len = read32(p); 189 | p += 4; 190 | q->args[n].envvar = alloc_str(p, len); 191 | p += len; 192 | 193 | q->args[n].type = *(p++); 194 | 195 | q->args[n].val = NULL; 196 | } 197 | 198 | q->files_count = read32(p); 199 | p += 4; 200 | q->files = (qcfile_t *)malloc(sizeof(qcfile_t) * q->files_count); 201 | for(n = 0; n < q->files_count; ++n) 202 | { 203 | len = read32(p); 204 | p += 4; 205 | q->files[n].name = alloc_str(p, len); 206 | p += len; 207 | 208 | len = read32(p); 209 | p += 4; 210 | q->files[n].data = (unsigned char *)malloc(len); 211 | memcpy(q->files[n].data, p, len); 212 | q->files[n].size = len; 213 | p += len; 214 | } 215 | 216 | len = read32(p); 217 | p += 4; 218 | q->pro_name = alloc_str(p, len); 219 | p += len; 220 | 221 | len = read32(p); 222 | p += 4; 223 | q->pro_file = alloc_str(p, len); 224 | p += len; 225 | 226 | len = read32(p); 227 | p += 4; 228 | q->qtinfo = alloc_str(p, len); 229 | p += len; 230 | 231 | return q; 232 | } 233 | 234 | static void qcdata_delete(qcdata_t *q) 235 | { 236 | int n; 237 | 238 | if(q->usage) 239 | free(q->usage); 240 | 241 | for(n = 0; n < q->args_count; ++n) 242 | { 243 | free(q->args[n].name); 244 | free(q->args[n].envvar); 245 | if(q->args[n].val) 246 | free(q->args[n].val); 247 | } 248 | 249 | for(n = 0; n < q->files_count; ++n) 250 | { 251 | free(q->files[n].name); 252 | free(q->files[n].data); 253 | } 254 | 255 | if(q->pro_name) 256 | free(q->pro_name); 257 | if(q->pro_file) 258 | free(q->pro_file); 259 | 260 | free(q); 261 | } 262 | 263 | static int find_arg(const qcarg_t *args, int count, const char *name) 264 | { 265 | int n; 266 | for(n = 0; n < count; ++n) 267 | { 268 | if(strcmp(args[n].name, name) == 0) 269 | return n; 270 | } 271 | return -1; 272 | } 273 | 274 | static int find_file(const qcfile_t *files, int count, const char *name) 275 | { 276 | int n; 277 | for(n = 0; n < count; ++n) 278 | { 279 | if(strcmp(files[n].name, name) == 0) 280 | return n; 281 | } 282 | return -1; 283 | } 284 | 285 | // adapted from qt 286 | static int set_envvar(const char *var, const char *val) 287 | { 288 | #if defined(_MSC_VER) && _MSC_VER >= 1400 289 | return (_putenv_s(var, val) == 0 ? 1 : 0); 290 | #else 291 | char *str; 292 | str = malloc(strlen(var) + 1 + strlen(val) + 1); 293 | strcpy(str, var); 294 | strcat(str, "="); 295 | strcat(str, val); 296 | return (putenv(str) == 0 ? 1 : 0); 297 | #endif 298 | } 299 | 300 | static char *get_envvar(const char *var) 301 | { 302 | return getenv(var); 303 | } 304 | 305 | static char *separators_to_native(const char *in) 306 | { 307 | char *out; 308 | 309 | #ifdef QC_OS_WIN 310 | int len; 311 | int n; 312 | 313 | out = strdup(in); 314 | len = strlen(in); 315 | for(n = 0; n < len; ++n) 316 | { 317 | if(out[n] == '/') 318 | out[n] = '\\'; 319 | } 320 | #else 321 | out = strdup(in); 322 | #endif 323 | 324 | return out; 325 | } 326 | 327 | static int file_exists(const char *path) 328 | { 329 | char *npath; 330 | int ret; 331 | #ifdef QC_OS_WIN 332 | struct _stat buf; 333 | #else 334 | struct stat buf; 335 | #endif 336 | 337 | npath = separators_to_native(path); 338 | 339 | #ifdef QC_OS_WIN 340 | ret = _stat(npath, &buf); 341 | #else 342 | ret = stat(npath, &buf); 343 | #endif 344 | 345 | free(npath); 346 | if(ret == 0) 347 | return 1; 348 | else 349 | return 0; 350 | } 351 | 352 | static char *check_qmake_path(const char *qtdir) 353 | { 354 | char *str; 355 | 356 | str = separators_to_native(qtdir); 357 | #ifdef QC_OS_WIN 358 | str = append_free(str, "\\qmake.exe"); 359 | #else 360 | str = append_free(str, "/qmake"); 361 | #endif 362 | if (qc_verbose) { 363 | printf("Check if \"%s\" exists\n", str); 364 | } 365 | if(file_exists(str)) 366 | { 367 | return str; 368 | } 369 | else 370 | { 371 | free(str); 372 | return NULL; 373 | } 374 | } 375 | 376 | static int qmake_query(const char *qmake_path, const char *var, char *out_buf, size_t buf_size) 377 | { 378 | char command[PATH_MAX]; 379 | int cnt = snprintf(command, sizeof(command) - 1, "%s -query %s", qmake_path, var); 380 | if (cnt > 0 && cnt < (int)sizeof(command)) 381 | { 382 | command[sizeof(command) - 1] = '\0'; // To be sure line has null-terminator 383 | return run_buffer_stdout(command, out_buf, buf_size); 384 | } 385 | return 0; // fail 386 | } 387 | 388 | static int qmake_query_maj_ver(const char *qmake_path, char *out_buf, size_t buf_size) 389 | { 390 | if (qmake_query(qmake_path, "QT_VERSION", out_buf, buf_size)) { 391 | int at = index_of(out_buf, '.'); 392 | if (at > 0) 393 | { 394 | out_buf[at] = '\0'; 395 | return 1; 396 | } 397 | } 398 | return 0; 399 | } 400 | 401 | // modifies contents of spec_path and returns pointer to spec name 402 | char *extract_spec_name(char *spec_path) 403 | { 404 | char *end = spec_path; 405 | while (!iscntrl(*end)) { 406 | if (*end == '/') { 407 | if (iscntrl(*(end+1))) { // next is end of line 408 | break; 409 | } else { 410 | spec_path = end + 1; 411 | end = spec_path + 1; 412 | } 413 | } else 414 | end++; 415 | } 416 | *end = 0; 417 | return spec_path; 418 | } 419 | 420 | int check_qtversion(char *path, char *version) 421 | { 422 | int res = 0; 423 | 424 | if (version) 425 | { 426 | char buf[20]; // version string output always small 427 | if (qmake_query_maj_ver(path, buf, sizeof(buf))) { 428 | res = !strcmp(version, buf); 429 | if (!res && qc_verbose) 430 | { 431 | printf("Warning: %s not for Qt %s\n", path, qtsearchtext); 432 | } 433 | } 434 | } 435 | else 436 | { 437 | res = 1; 438 | } 439 | 440 | return res; 441 | } 442 | 443 | static char* parse_qtselect(char *src) 444 | { 445 | unsigned long int ver; 446 | if (src) { 447 | if (src[0] == 'q' && src[1] == 't') 448 | src += 2; 449 | 450 | ver = strtoul(src, NULL, 10); 451 | if (ver > 0 && ver < ULONG_MAX) { 452 | qc_qtselect = strdup(src); 453 | qtsearchtext = qc_qtselect; 454 | return qc_qtselect; 455 | } 456 | } 457 | return NULL; 458 | } 459 | 460 | static char *find_qmake() 461 | { 462 | char *qtdir; 463 | char *path; 464 | char try_syspath = 1; 465 | 466 | if (!qc_qtselect) 467 | parse_qtselect(get_envvar("QT_SELECT")); 468 | 469 | 470 | qtdir = ex_qtdir; 471 | if(qtdir) 472 | { 473 | qtdir = append_free(strdup(qtdir), "\\bin"); 474 | path = check_qmake_path(qtdir); 475 | free(qtdir); 476 | 477 | if(path) 478 | { 479 | if (!check_qtversion(path, qc_qtselect)) 480 | return NULL; 481 | return path; 482 | } 483 | try_syspath = 0; 484 | } 485 | if(qc_verbose) 486 | printf("Warning: qmake not found via --qtdir\n"); 487 | 488 | qtdir = get_envvar("QTDIR"); 489 | if(qtdir) 490 | { 491 | qtdir = append_free(strdup(qtdir), "\\bin"); 492 | path = check_qmake_path(qtdir); 493 | free(qtdir); 494 | 495 | if(path) 496 | { 497 | if (!check_qtversion(path, qc_qtselect)) 498 | return NULL; 499 | return path; 500 | } 501 | try_syspath = 0; 502 | } 503 | if(qc_verbose) 504 | printf("Warning: qmake not found via %%QTDIR%%\n"); 505 | 506 | /* if not set explicitly try something implicit */ 507 | if (try_syspath) { 508 | char *paths = strdup(get_envvar("PATH")); 509 | qtdir = paths; 510 | while (1) 511 | { 512 | int at = index_of(qtdir, path_separator); 513 | if (at > 0) 514 | qtdir[at] = '\0'; 515 | path = check_qmake_path(qtdir); 516 | if (path && check_qtversion(path, qc_qtselect)) 517 | { 518 | free(paths); 519 | return path; 520 | } 521 | 522 | if (at > 0) 523 | qtdir += at + 1; 524 | else 525 | break; 526 | } 527 | free(paths); 528 | } 529 | 530 | if(qc_verbose) 531 | printf("Warning: qmake not found in PATH\n"); 532 | 533 | return NULL; 534 | } 535 | 536 | static int run_buffer_stdout(const char *command, char *out_buf, size_t buf_size) 537 | { 538 | FILE *file; 539 | 540 | file = popen(command, "r"); 541 | if (file) 542 | { 543 | size_t bytes_left = buf_size - 1; // 1 for null terminator 544 | size_t bytes_read; 545 | while (bytes_left && (bytes_read = fread(out_buf, 1, bytes_left, file)) > 0) 546 | bytes_left -= bytes_read; 547 | 548 | out_buf[buf_size - bytes_left - 1] = '\0'; 549 | pclose(file); 550 | 551 | return 1; // ok 552 | } 553 | 554 | out_buf[0] = 0; // just in case 555 | return 0; // fail 556 | } 557 | 558 | static int run_silent_stdout(const char *cmd) 559 | { 560 | char *str; 561 | int ret; 562 | 563 | str = strdup(cmd); 564 | #ifdef QC_OS_WIN 565 | str = append_free(str, " >NUL"); 566 | #else 567 | str = append_free(str, " >/dev/null"); 568 | #endif 569 | ret = system(str); 570 | free(str); 571 | 572 | return ret; 573 | } 574 | 575 | static int run_silent_all(const char *cmd) 576 | { 577 | char *str; 578 | int ret; 579 | 580 | str = strdup(cmd); 581 | #ifdef QC_OS_WIN 582 | str = append_free(str, " >NUL 2>&1"); 583 | #else 584 | str = append_free(str, " >/dev/null 2>&1"); 585 | #endif 586 | ret = system(str); 587 | free(str); 588 | 589 | return ret; 590 | } 591 | 592 | static int run_conflog_all(const char *cmd) 593 | { 594 | char *str; 595 | int ret; 596 | 597 | str = strdup(cmd); 598 | #ifdef QC_OS_WIN 599 | str = append_free(str, " >..\\conf.log 2>&1"); 600 | #else 601 | str = append_free(str, " >../conf.log 2>&1"); 602 | #endif 603 | if (qc_verbose) 604 | printf("Starting \"%s\"\n", str); 605 | ret = system(str); 606 | free(str); 607 | 608 | return ret; 609 | } 610 | 611 | static int qc_ensuredir(const char *path) 612 | { 613 | #ifdef QC_OS_WIN 614 | if(_mkdir(path) == 0) 615 | return 1; 616 | else if(errno == EEXIST) 617 | return 1; 618 | else 619 | return 0; 620 | #else 621 | if(mkdir(path, S_IRWXU | S_IRWXG) == 0) 622 | return 1; 623 | else if(errno == EEXIST) 624 | return 1; 625 | else 626 | return 0; 627 | #endif 628 | } 629 | 630 | static int qc_chdir(const char *path) 631 | { 632 | int ret; 633 | 634 | #ifdef QC_OS_WIN 635 | ret = _chdir(path); 636 | #else 637 | ret = chdir(path); 638 | #endif 639 | 640 | if(ret == 0) 641 | return 1; 642 | else 643 | return 0; 644 | } 645 | 646 | static int qc_removedir(const char *path) 647 | { 648 | char *str; 649 | int ret; 650 | 651 | #ifdef QC_OS_WIN 652 | str = strdup("deltree /y "); 653 | str = append_free(str, path); 654 | ret = run_silent_all(str); 655 | free(str); 656 | if(ret != 0) 657 | { 658 | str = strdup("rmdir /s /q "); 659 | str = append_free(str, path); 660 | ret = run_silent_all(str); 661 | free(str); 662 | } 663 | #else 664 | str = strdup("rm -rf "); 665 | str = append_free(str, path); 666 | ret = system(str); 667 | free(str); 668 | #endif 669 | 670 | if(ret == 0) 671 | return 1; 672 | else 673 | return 0; 674 | } 675 | 676 | static int gen_file(qcdata_t *q, const char *name, const char *dest) 677 | { 678 | int at; 679 | char *str, *npath; 680 | FILE *fp; 681 | 682 | at = find_file(q->files, q->files_count, name); 683 | if(at == -1) 684 | return 0; 685 | 686 | str = strdup(dest); 687 | str = append_free(str, "/"); 688 | str = append_free(str, name); 689 | npath = separators_to_native(str); 690 | free(str); 691 | fp = fopen(npath, "wb"); 692 | free(npath); 693 | if(!fp) 694 | return 0; 695 | /*if(*/fwrite(q->files[at].data, q->files[at].size, 1, fp);/* < 1) 696 | { 697 | fclose(fp); 698 | return 0; 699 | }*/ 700 | fclose(fp); 701 | return 1; 702 | } 703 | 704 | static int gen_files(qcdata_t *q, const char *dest) 705 | { 706 | if(!gen_file(q, "modules.cpp", dest)) 707 | return 0; 708 | if(!gen_file(q, "modules_new.cpp", dest)) 709 | return 0; 710 | if(!gen_file(q, "conf4.h", dest)) 711 | return 0; 712 | if(!gen_file(q, "conf4.cpp", dest)) 713 | return 0; 714 | if(!gen_file(q, "conf4.pro", dest)) 715 | return 0; 716 | return 1; 717 | } 718 | 719 | static int try_make(const char *makecmd, char **maketool) 720 | { 721 | char *str; 722 | int ret; 723 | 724 | str = strdup(makecmd); 725 | str = append_free(str, " clean"); 726 | ret = run_conflog_all(str); 727 | free(str); 728 | if(ret != 0) 729 | return 0; 730 | 731 | if(run_conflog_all(makecmd) != 0) { 732 | if (qc_verbose) 733 | printf("\"%s\" failed\n", makecmd); 734 | return 0; 735 | } 736 | 737 | *maketool = strdup(makecmd); 738 | return 1; 739 | } 740 | 741 | static char *maketool_list_common[] = 742 | { 743 | "mingw32-make", 744 | "make", 745 | "jom", 746 | "nmake", 747 | NULL 748 | }; 749 | 750 | static char *maketool_list_mingw[] = 751 | { 752 | "make", 753 | "mingw32-make", 754 | NULL 755 | }; 756 | 757 | static char *maketool_list_vs[] = 758 | { 759 | "jom", 760 | "nmake", 761 | NULL 762 | }; 763 | 764 | static int do_conf_create(qcdata_t *q, const char *qmake_path, const char *spec, char **maketool) 765 | { 766 | char *str; 767 | int n; 768 | int at; 769 | char **maketool_list; 770 | 771 | if(!qc_ensuredir(qconftemp_path)) 772 | return 0; 773 | 774 | if(!gen_files(q, qconftemp_path)) 775 | return 0; 776 | 777 | if(!qc_chdir(qconftemp_path)) 778 | return 0; 779 | 780 | // TODO: support -spec once QC_MAKESPEC matters 781 | str = strdup(qmake_path); 782 | str = append_free(str, " conf4.pro"); 783 | if(run_silent_stdout(str) != 0) 784 | { 785 | free(str); 786 | qc_chdir(".."); 787 | return 0; 788 | } 789 | free(str); 790 | 791 | at = -1; 792 | if (strstr(spec, "win32-msvc")) { 793 | maketool_list = maketool_list_vs; 794 | } else if(strstr(spec, "win32-g++")) { 795 | maketool_list = maketool_list_mingw; 796 | } else { 797 | maketool_list = maketool_list_common; 798 | } 799 | for(n = 0; maketool_list[n]; ++n) 800 | { 801 | if(qc_verbose) 802 | printf("Trying \"%s\"\n", maketool_list[n]); 803 | if(try_make(maketool_list[n], maketool)) 804 | { 805 | at = n; 806 | break; 807 | } 808 | } 809 | 810 | qc_chdir(".."); 811 | if(at == -1) 812 | return 0; 813 | 814 | return 1; 815 | } 816 | 817 | static int do_conf_run() 818 | { 819 | char *str, *npath; 820 | int ret; 821 | 822 | str = strdup(qconftemp_path); 823 | str = append_free(str, "/conf"); 824 | npath = separators_to_native(str); 825 | free(str); 826 | ret = system(npath); 827 | free(npath); 828 | 829 | return ret; 830 | } 831 | 832 | static void cleanup_qconftemp() 833 | { 834 | qc_removedir(qconftemp_path); 835 | } 836 | 837 | static void try_print_var(const char *var, const char *val) 838 | { 839 | printf("%s=", var); 840 | if(val) 841 | printf("%s", val); 842 | printf("\n"); 843 | } 844 | 845 | static int do_conf(qcdata_t *q, const char *argv0) 846 | { 847 | char *qmake_path; 848 | char *maketool; 849 | int qt_maj_version = 0; 850 | char *specs_name = NULL; 851 | int n; 852 | int ret; 853 | 854 | printf("Configuring %s ...\n", q->pro_name); 855 | 856 | if(qc_verbose) 857 | { 858 | printf("\n"); 859 | for(n = 0; n < q->args_count; ++n) 860 | try_print_var(q->args[n].envvar, q->args[n].val); 861 | } 862 | 863 | printf("Verifying Qt build environment ... "); 864 | fflush(stdout); 865 | 866 | if(qc_verbose) 867 | printf("\n"); 868 | 869 | qmake_path = find_qmake(); 870 | if(!qmake_path) 871 | { 872 | if(qc_verbose) 873 | printf(" -> fail\n"); 874 | else 875 | printf("fail\n"); 876 | printf("\n"); 877 | printf("Reason: Unable to find the 'qmake' tool for Qt %s.\n", qtsearchtext); 878 | printf("\n"); 879 | printf("%s", q->qtinfo); 880 | return 0; 881 | } 882 | if(qc_verbose) 883 | printf("qmake found in %s\n", qmake_path); 884 | 885 | // figure out what version it is. 886 | { 887 | char buf[20]; // version string output always small 888 | if (qmake_query_maj_ver(qmake_path, buf, sizeof(buf))) { 889 | qt_maj_version = strtoul(buf, NULL, 10); 890 | if (qt_maj_version == ULONG_MAX) 891 | qt_maj_version = 0; 892 | } 893 | if (qt_maj_version == 0) { 894 | if(qc_verbose) { 895 | printf(" -> fail\n"); 896 | printf("Qt major version is not parsable\n"); 897 | } else 898 | printf("fail\n"); 899 | free(qmake_path); 900 | return 0; 901 | } 902 | } 903 | 904 | // find specc name 905 | { 906 | char *spec = get_envvar("QMAKESPEC"); 907 | if (!spec) { 908 | // try to find default spec 909 | if (qt_maj_version > 4) { 910 | char buf[32]; 911 | if (qmake_query(qmake_path, "QMAKE_XSPEC", buf, sizeof(buf))) // or QMAKE_SPEC ? 912 | specs_name = strdup(buf); 913 | // it's possible to compute full path like QT_HOST_DATA/QMAKE_XSPEC 914 | } else { 915 | char *qmake_conf, buf[1024]; 916 | FILE *fp; 917 | qmake_query(qmake_path, "QMAKE_MKSPECS", buf, sizeof(buf)); 918 | qmake_conf = append_free(strdup(buf), "/default/qmake.conf"); 919 | fp = fopen(qmake_conf, "r"); 920 | free(qmake_conf); 921 | if (fp) { 922 | size_t br; 923 | if ((br = fread(buf, 1, sizeof(buf) - 1, fp)) > 0) { 924 | char *str, *end; 925 | buf[br] = 0; 926 | str = strstr(buf, "QMAKESPEC_ORIGINAL="); 927 | if (str) { 928 | str = extract_spec_name(str); 929 | if (str) { 930 | specs_name = strdup(str); 931 | } 932 | } 933 | } 934 | fclose(fp); 935 | } 936 | } 937 | } else { 938 | char *s = strdup(spec); 939 | specs_name = extract_spec_name(s); 940 | if (specs_name) { 941 | specs_name = strdup(specs_name); 942 | } 943 | free(s); 944 | } 945 | } 946 | 947 | // TODO: in verbose mode, print out default makespec and what we're 948 | // overriding the makespec to (if any). since at this time we don't 949 | // ever override the makespec on windows, we don't need this yet. 950 | 951 | cleanup_qconftemp(); 952 | maketool = NULL; 953 | if(!do_conf_create(q, qmake_path, specs_name, &maketool)) 954 | { 955 | cleanup_qconftemp(); 956 | if(qc_verbose) 957 | printf(" -> fail\n"); 958 | else 959 | printf("fail\n"); 960 | printf("\n"); 961 | printf("Reason: There was an error compiling 'conf'. See conf.log for details.\n"); 962 | printf("\n"); 963 | printf("%s", q->qtinfo); 964 | 965 | if(qc_verbose) 966 | { 967 | printf("conf.log:\n"); 968 | system("type conf.log"); 969 | } 970 | 971 | free(qmake_path); 972 | return 0; 973 | } 974 | 975 | set_envvar("QC_COMMAND", argv0); 976 | set_envvar("QC_PROFILE", q->pro_file); 977 | set_envvar("QC_QMAKE", qmake_path); 978 | // TODO: unix configure will set QC_MAKESPEC here if it needs to 979 | // override the mkspec. currently, it only does this for macx-xcode 980 | // so the behavior doesn't apply to windows yet. 981 | set_envvar("QC_MAKETOOL", maketool); 982 | 983 | free(qmake_path); 984 | 985 | ret = do_conf_run(); 986 | if(ret == 1) 987 | { 988 | cleanup_qconftemp(); 989 | printf("\n"); 990 | free(maketool); 991 | return 0; 992 | } 993 | else if(ret != 0) 994 | { 995 | cleanup_qconftemp(); 996 | if(qc_verbose) 997 | printf(" -> fail\n"); 998 | else 999 | printf("fail\n"); 1000 | printf("\n"); 1001 | printf("Reason: Unexpected error launching 'conf'\n"); 1002 | printf("\n"); 1003 | free(maketool); 1004 | return 0; 1005 | } 1006 | 1007 | cleanup_qconftemp(); 1008 | printf("\n"); 1009 | printf("Good, your configure finished. Now run %s.\n", maketool); 1010 | printf("\n"); 1011 | free(maketool); 1012 | 1013 | return 1; 1014 | } 1015 | 1016 | int main(int argc, char **argv) 1017 | { 1018 | unsigned char *data; 1019 | unsigned int size; 1020 | qcdata_t *q; 1021 | int n; 1022 | int at; 1023 | int quit; 1024 | char *arg, *var, *val; 1025 | 1026 | if(!embed_get_data(argv[0], &data, &size)) 1027 | { 1028 | fprintf(stderr, "Error: Can't import data.\n"); 1029 | return 1; 1030 | } 1031 | 1032 | q = parse_data(data, size); 1033 | if(!q) 1034 | { 1035 | fprintf(stderr, "Error: Can't parse internal data.\n"); 1036 | free(data); 1037 | return 1; 1038 | } 1039 | 1040 | if(q->usage) 1041 | { 1042 | val = find_replace(q->usage, "$0", argv[0]); 1043 | free(q->usage); 1044 | q->usage = val; 1045 | } 1046 | 1047 | quit = 0; 1048 | for(n = 1; n < argc && !quit; ++n) 1049 | { 1050 | arg = argv[n]; 1051 | 1052 | if(arg[0] != '-' || arg[1] != '-') 1053 | { 1054 | printf("%s", q->usage); 1055 | quit = 1; 1056 | break; 1057 | } 1058 | 1059 | at = index_of(arg + 2, '='); 1060 | if(at != -1) 1061 | { 1062 | var = alloc_str((unsigned char *)arg + 2, at); 1063 | val = strdup(arg + 2 + at + 1); 1064 | } 1065 | else 1066 | { 1067 | var = strdup(arg + 2); 1068 | val = 0; 1069 | } 1070 | 1071 | if(strcmp(var, "help") == 0) 1072 | { 1073 | printf("%s", q->usage); 1074 | quit = 1; 1075 | } 1076 | else if(strcmp(var, "verbose") == 0) 1077 | { 1078 | qc_verbose = 1; 1079 | set_envvar("QC_VERBOSE", "Y"); 1080 | } 1081 | else if(strcmp(var, "prefix") == 0) 1082 | { 1083 | prefix = strdup(val); 1084 | } 1085 | else if(strcmp(var, "bindir") == 0) 1086 | { 1087 | bindir = strdup(val); 1088 | } 1089 | else if(strcmp(var, "includedir") == 0) 1090 | { 1091 | includedir = strdup(val); 1092 | } 1093 | else if(strcmp(var, "datadir") == 0) 1094 | { 1095 | datadir = strdup(val); 1096 | } 1097 | else if(strcmp(var, "libdir") == 0) 1098 | { 1099 | libdir = strdup(val); 1100 | } 1101 | else if(strcmp(var, "qtselect") == 0) 1102 | { 1103 | if (val && strlen(val)) 1104 | qc_qtselect = parse_qtselect(val); 1105 | } 1106 | else 1107 | { 1108 | at = find_arg(q->args, q->args_count, var); 1109 | if(at != -1) 1110 | { 1111 | // keep a stash of ex_qtdir 1112 | if(strcmp(var, "qtdir") == 0) 1113 | { 1114 | if(ex_qtdir) 1115 | free(ex_qtdir); 1116 | ex_qtdir = strdup(val); 1117 | } 1118 | 1119 | if(q->args[at].val) 1120 | free(q->args[at].val); 1121 | 1122 | if(q->args[at].type == ArgValue) 1123 | q->args[at].val = strdup(val); 1124 | else // ArgFlag 1125 | q->args[at].val = strdup("Y"); 1126 | 1127 | set_envvar(q->args[at].envvar, q->args[at].val); 1128 | } 1129 | else 1130 | { 1131 | printf("%s", q->usage); 1132 | quit = 1; 1133 | } 1134 | } 1135 | 1136 | free(var); 1137 | if(val) 1138 | free(val); 1139 | } 1140 | 1141 | if(quit) 1142 | { 1143 | qcdata_delete(q); 1144 | if(ex_qtdir) 1145 | free(ex_qtdir); 1146 | 1147 | if(qc_qtselect) 1148 | free(qc_qtselect); 1149 | 1150 | if(prefix) 1151 | free(prefix); 1152 | 1153 | if(bindir) 1154 | free(bindir); 1155 | 1156 | if(includedir) 1157 | free(includedir); 1158 | 1159 | if(libdir) 1160 | free(libdir); 1161 | 1162 | if(datadir) 1163 | free(datadir); 1164 | 1165 | return 1; 1166 | } 1167 | 1168 | if(prefix) 1169 | { 1170 | set_envvar("PREFIX", prefix); 1171 | if(!libdir) 1172 | libdir = append_str(prefix, "/lib"); 1173 | 1174 | if(!bindir) 1175 | bindir = append_str(prefix, "/bin"); 1176 | 1177 | if(!includedir) 1178 | includedir = append_str(prefix, "/include"); 1179 | 1180 | if(!datadir) 1181 | datadir = append_str(prefix, "/share"); 1182 | } 1183 | 1184 | if(libdir) 1185 | set_envvar("LIBDIR", libdir); 1186 | 1187 | if(bindir) 1188 | set_envvar("BINDIR", bindir); 1189 | 1190 | if(includedir) 1191 | set_envvar("INCLUDEDIR", includedir); 1192 | 1193 | if(datadir) 1194 | set_envvar("DATADIR", datadir); 1195 | 1196 | if(libdir) 1197 | set_envvar("LIBDIR", libdir); 1198 | 1199 | n = do_conf(q, argv[0]); 1200 | qcdata_delete(q); 1201 | if(ex_qtdir) 1202 | free(ex_qtdir); 1203 | 1204 | if(qc_qtselect) 1205 | free(qc_qtselect); 1206 | 1207 | if(prefix) 1208 | free(prefix); 1209 | 1210 | if(bindir) 1211 | free(bindir); 1212 | 1213 | if(includedir) 1214 | free(includedir); 1215 | 1216 | if(libdir) 1217 | free(libdir); 1218 | 1219 | if(datadir) 1220 | free(datadir); 1221 | 1222 | if(n) 1223 | return 0; 1224 | else 1225 | return 1; 1226 | } 1227 | -------------------------------------------------------------------------------- /conf/conf4.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2004-2008 Justin Karneges 3 | 4 | This file is free software; unlimited permission is given to copy and/or 5 | distribute it, with or without modifications, as long as this notice is 6 | preserved. 7 | */ 8 | 9 | #include "conf4.h" 10 | 11 | #include 12 | #include 13 | #include 14 | #ifndef PATH_MAX 15 | #ifdef Q_OS_WIN 16 | #define PATH_MAX 260 17 | #endif 18 | #endif 19 | 20 | class MocTestObject : public QObject { 21 | 22 | Q_OBJECT 23 | public: 24 | MocTestObject() {} 25 | }; 26 | 27 | QString qc_getenv(const QString &var) 28 | { 29 | char *p = ::getenv(var.toLatin1().data()); 30 | if (!p) 31 | return QString(); 32 | return QString(p); 33 | } 34 | 35 | QStringList qc_pathlist() 36 | { 37 | QStringList list; 38 | QString path = qc_getenv("PATH"); 39 | if (!path.isEmpty()) { 40 | #if QT_VERSION >= 0x060000 41 | Qt::SplitBehavior flags = Qt::SkipEmptyParts; 42 | #else 43 | QString::SplitBehavior flags = QString::SkipEmptyParts; 44 | #endif 45 | #ifdef Q_OS_WIN 46 | list = path.split(';', flags); 47 | #else 48 | list = path.split(':', flags); 49 | #endif 50 | } 51 | #ifdef Q_OS_WIN 52 | list.prepend("."); 53 | #endif 54 | return list; 55 | } 56 | 57 | QString qc_findprogram(const QString &prog) 58 | { 59 | QString out; 60 | QStringList list = qc_pathlist(); 61 | for (int n = 0; n < list.count(); ++n) { 62 | QFileInfo fi(list[n] + '/' + prog); 63 | if (fi.exists() && fi.isExecutable()) { 64 | out = fi.filePath(); 65 | break; 66 | } 67 | 68 | #ifdef Q_OS_WIN 69 | // on windows, be sure to look for .exe 70 | if (prog.right(4).toLower() != ".exe") { 71 | fi = QFileInfo(list[n] + '/' + prog + ".exe"); 72 | if (fi.exists() && fi.isExecutable()) { 73 | out = fi.filePath(); 74 | break; 75 | } 76 | } 77 | #endif 78 | } 79 | return out; 80 | } 81 | 82 | QString qc_findself(const QString &argv0) 83 | { 84 | #ifdef Q_OS_WIN 85 | if (argv0.contains('\\')) 86 | #else 87 | if (argv0.contains('/')) 88 | #endif 89 | return argv0; 90 | else 91 | return qc_findprogram(argv0); 92 | } 93 | 94 | int qc_run_program_or_command(const QString &prog, const QStringList &args, const QString &command, QByteArray *out, 95 | bool showOutput) 96 | { 97 | if (out) 98 | out->clear(); 99 | 100 | QProcess process; 101 | process.setReadChannel(QProcess::StandardOutput); 102 | 103 | if (!prog.isEmpty()) 104 | process.start(prog, args); 105 | else if (!command.isEmpty()) 106 | process.start(command); 107 | else 108 | return -1; 109 | 110 | if (!process.waitForStarted(-1)) 111 | return -1; 112 | 113 | QByteArray buf; 114 | 115 | while (process.waitForReadyRead(-1)) { 116 | buf = process.readAllStandardOutput(); 117 | if (out) 118 | out->append(buf); 119 | if (showOutput) 120 | fprintf(stdout, "%s", buf.data()); 121 | 122 | buf = process.readAllStandardError(); 123 | if (showOutput) 124 | fprintf(stderr, "%s", buf.data()); 125 | } 126 | 127 | buf = process.readAllStandardError(); 128 | if (showOutput) 129 | fprintf(stderr, "%s", buf.data()); 130 | 131 | // calling waitForReadyRead will cause the process to eventually be 132 | // marked as finished, so we should not need to separately call 133 | // waitForFinished. however, we will do it anyway just to be safe. 134 | // we won't check the return value since false could still mean 135 | // success (if the process had already been marked as finished). 136 | process.waitForFinished(-1); 137 | 138 | if (process.exitStatus() != QProcess::NormalExit) 139 | return -1; 140 | 141 | return process.exitCode(); 142 | } 143 | 144 | int qc_runcommand(const QString &command, QByteArray *out, bool showOutput) 145 | { 146 | return qc_run_program_or_command(QString(), QStringList(), command, out, showOutput); 147 | } 148 | 149 | int qc_runprogram(const QString &prog, const QStringList &args, QByteArray *out, bool showOutput) 150 | { 151 | return qc_run_program_or_command(prog, args, QString(), out, showOutput); 152 | } 153 | 154 | bool qc_removedir(const QString &dirPath) 155 | { 156 | QDir dir(dirPath); 157 | if (!dir.exists()) 158 | return false; 159 | QStringList list = dir.entryList(); 160 | foreach (QString s, list) { 161 | if (s == "." || s == "..") 162 | continue; 163 | QFileInfo fi(dir.filePath(s)); 164 | if (fi.isDir()) { 165 | if (!qc_removedir(fi.filePath())) 166 | return false; 167 | } else { 168 | if (!dir.remove(s)) 169 | return false; 170 | } 171 | } 172 | QString dirName = dir.dirName(); 173 | if (!dir.cdUp()) 174 | return false; 175 | if (!dir.rmdir(dirName)) 176 | return false; 177 | return true; 178 | } 179 | 180 | // simple command line arguemnts splitter able to understand quoted args. 181 | // the splitter removes quotes and unescapes symbols as well. 182 | QStringList qc_splitflags(const QString &flags) 183 | { 184 | QStringList ret; 185 | bool searchStart = true; 186 | bool inQuotes = false; 187 | bool escaped = false; 188 | QChar quote, backslash = QLatin1Char('\\'); 189 | QString buf; 190 | #ifdef PATH_MAX 191 | buf.reserve(PATH_MAX); 192 | #endif 193 | for (int i = 0; i < flags.length(); i++) { 194 | if (searchStart && flags[i].isSpace()) { 195 | continue; 196 | } 197 | if (searchStart) { 198 | searchStart = false; 199 | buf.clear(); 200 | } 201 | if (escaped) { 202 | buf += flags[i]; 203 | escaped = false; 204 | continue; 205 | } 206 | // buf += flags[i]; 207 | if (inQuotes) { 208 | if (quote == QLatin1Char('\'')) { 209 | if (flags[i] == quote) { 210 | inQuotes = false; 211 | continue; 212 | } 213 | } else { // we are in double quoetes 214 | if (i < flags.length() - 1 && flags[i] == backslash 215 | && (flags[i + 1] == QLatin1Char('"') || flags[i + 1] == backslash)) { 216 | // if next symbol is one of in parentheses ("\) 217 | escaped = true; 218 | continue; 219 | } 220 | } 221 | } else { 222 | if (flags[i].isSpace()) { 223 | ret.append(buf); 224 | searchStart = true; 225 | buf.clear(); 226 | continue; 227 | #ifndef Q_OS_WIN /* on windows backslash is just a path separator */ 228 | } else if (flags[i] == backslash) { 229 | escaped = true; 230 | continue; // just add next symbol 231 | #endif 232 | } else if (flags[i] == QLatin1Char('\'') || flags[i] == QLatin1Char('"')) { 233 | inQuotes = true; 234 | quote = flags[i]; 235 | continue; 236 | } 237 | } 238 | buf += flags[i]; 239 | } 240 | if (buf.size()) { 241 | ret.append(buf); 242 | } 243 | return ret; 244 | } 245 | 246 | void qc_splitcflags(const QString &cflags, QStringList *incs, QStringList *otherflags) 247 | { 248 | incs->clear(); 249 | otherflags->clear(); 250 | 251 | QStringList cflagsList = qc_splitflags(cflags); 252 | for (int n = 0; n < cflagsList.count(); ++n) { 253 | QString str = cflagsList[n]; 254 | if (str.startsWith("-I")) { 255 | // we want everything except the leading "-I" 256 | incs->append(str.remove(0, 2)); 257 | } else { 258 | // we want whatever is left 259 | otherflags->append(str); 260 | } 261 | } 262 | } 263 | 264 | QString qc_escapeArg(const QString &str) 265 | { 266 | QString out; 267 | for (int n = 0; n < (int)str.length(); ++n) { 268 | if (str[n] == '-') 269 | out += '_'; 270 | else 271 | out += str[n]; 272 | } 273 | return out; 274 | } 275 | 276 | QString qc_trim_char(const QString &s, const QChar &ch) 277 | { 278 | if (s.startsWith(ch) && s.endsWith(ch)) { 279 | return s.mid(1, s.size() - 2); 280 | } 281 | return s; 282 | } 283 | 284 | // removes surrounding quotes, removes trailing slashes, converts to native separators. 285 | // accepts unescaped but possible quoted path 286 | QString qc_normalize_path(const QString &str) 287 | { 288 | QString path = str.trimmed(); 289 | path = qc_trim_char(path, QLatin1Char('"')); 290 | path = qc_trim_char(path, QLatin1Char('\'')); 291 | 292 | // It's OK to use unix style'/' paths on windows Qt handles this without any problems. 293 | // Using Windows-style '\\' can leads strange compilation error with MSYS which uses 294 | // unix style. 295 | QLatin1Char nativeSep('/'); 296 | #ifdef Q_OS_WIN 297 | path.replace(QLatin1Char('\\'), QLatin1Char('/')); 298 | #endif 299 | // trim trailing slashes 300 | while (path.length() && path[path.length() - 1] == nativeSep) { 301 | path.resize(path.length() - 1); 302 | } 303 | return path; 304 | } 305 | 306 | // escape filesystem path to be added to qmake pro/pri file. 307 | QString qc_escape_string_var(const QString &str) 308 | { 309 | QString path = str; 310 | path.replace(QLatin1Char('\\'), QLatin1String("\\\\")).replace(QLatin1Char('"'), QLatin1String("\\\"")); 311 | if (path.indexOf(QLatin1Char(' ')) != -1) { // has spaces 312 | return QLatin1Char('"') + path + QLatin1Char('"'); 313 | } 314 | return path; 315 | } 316 | 317 | // escapes each path in incs and join into single string suiable for INCLUDEPATH var 318 | QString qc_prepare_includepath(const QStringList &incs) 319 | { 320 | if (incs.empty()) { 321 | return QString(); 322 | } 323 | QStringList ret; 324 | foreach (const QString &path, incs) { 325 | ret.append(qc_escape_string_var(path)); 326 | } 327 | return ret.join(QLatin1String(" ")); 328 | } 329 | 330 | // escapes each path in libs and to make it suiable for LIBS var 331 | // notice, entries of libs are every single arg for linker. 332 | QString qc_prepare_libs(const QStringList &libs) 333 | { 334 | if (libs.isEmpty()) { 335 | return QString(); 336 | } 337 | QSet pathSet; 338 | QStringList paths; 339 | QStringList ordered; 340 | foreach (const QString &arg, libs) { 341 | if (arg.startsWith(QLatin1String("-L"))) { 342 | QString path = qc_escape_string_var(arg.mid(2)); 343 | if (!pathSet.contains(path)) { 344 | pathSet.insert(path); 345 | paths.append(path); 346 | } 347 | } else if (arg.startsWith(QLatin1String("-l"))) { 348 | ordered.append(arg); 349 | } else { 350 | ordered.append(qc_escape_string_var(arg)); 351 | } 352 | } 353 | QString ret; 354 | if (paths.size()) { 355 | ret += (QLatin1String(" -L") + paths.join(QLatin1String(" -L")) + QLatin1Char(' ')); 356 | } 357 | return ret + ordered.join(QLatin1String(" ")); 358 | } 359 | 360 | //---------------------------------------------------------------------------- 361 | // ConfObj 362 | //---------------------------------------------------------------------------- 363 | ConfObj::ConfObj(Conf *c) 364 | { 365 | conf = c; 366 | conf->added(this); 367 | required = false; 368 | disabled = false; 369 | success = false; 370 | } 371 | 372 | ConfObj::~ConfObj() {} 373 | 374 | QString ConfObj::checkString() const { return QString("Checking for %1 ...").arg(name()); } 375 | 376 | QString ConfObj::resultString() const 377 | { 378 | if (success) 379 | return "yes"; 380 | else 381 | return "no"; 382 | } 383 | 384 | //---------------------------------------------------------------------------- 385 | // qc_internal_pkgconfig 386 | //---------------------------------------------------------------------------- 387 | class qc_internal_pkgconfig : public ConfObj { 388 | public: 389 | QString pkgname, desc; 390 | VersionMode mode; 391 | QString req_ver; 392 | 393 | qc_internal_pkgconfig(Conf *c, const QString &_name, const QString &_desc, VersionMode _mode, 394 | const QString &_req_ver) : 395 | ConfObj(c), 396 | pkgname(_name), desc(_desc), mode(_mode), req_ver(_req_ver) 397 | { 398 | } 399 | 400 | QString name() const { return desc; } 401 | QString shortname() const { return pkgname; } 402 | 403 | bool exec() 404 | { 405 | QStringList incs; 406 | QString version, libs, other; 407 | if (!conf->findPkgConfig(pkgname, mode, req_ver, &version, &incs, &libs, &other)) 408 | return false; 409 | 410 | for (int n = 0; n < incs.count(); ++n) 411 | conf->addIncludePath(incs[n]); 412 | if (!libs.isEmpty()) 413 | conf->addLib(libs); 414 | // if(!other.isEmpty()) 415 | // conf->addExtra(QString("QMAKE_CFLAGS += %1\n").arg(other)); 416 | 417 | if (!required) 418 | conf->addDefine("HAVE_PKG_" + qc_escapeArg(pkgname).toUpper()); 419 | 420 | return true; 421 | } 422 | }; 423 | 424 | //---------------------------------------------------------------------------- 425 | // Conf 426 | //---------------------------------------------------------------------------- 427 | Conf::Conf() 428 | { 429 | // TODO: no more vars? 430 | // vars.insert("QMAKE_INCDIR_X11", new QString(X11_INC)); 431 | // vars.insert("QMAKE_LIBDIR_X11", new QString(X11_LIBDIR)); 432 | // vars.insert("QMAKE_LIBS_X11", new QString(X11_LIB)); 433 | // vars.insert("QMAKE_CC", CC); 434 | 435 | debug_enabled = false; 436 | first_debug = true; 437 | } 438 | 439 | Conf::~Conf() { qDeleteAll(list); } 440 | 441 | void Conf::added(ConfObj *o) { list.append(o); } 442 | 443 | QString Conf::getenv(const QString &var) { return qc_getenv(var); } 444 | 445 | void Conf::debug(const QString &s) 446 | { 447 | if (debug_enabled) { 448 | if (first_debug) 449 | printf("\n"); 450 | first_debug = false; 451 | printf(" * %s\n", qPrintable(s)); 452 | } 453 | } 454 | 455 | bool Conf::exec() 456 | { 457 | for (int n = 0; n < list.count(); ++n) { 458 | ConfObj *o = list[n]; 459 | 460 | // if this was a disabled-by-default option, check if it was enabled 461 | if (o->disabled) { 462 | QString v = QString("QC_ENABLE_") + qc_escapeArg(o->shortname()); 463 | if (getenv(v) != "Y") 464 | continue; 465 | } 466 | // and the opposite? 467 | else { 468 | QString v = QString("QC_DISABLE_") + qc_escapeArg(o->shortname()); 469 | if (getenv(v) == "Y") 470 | continue; 471 | } 472 | 473 | bool output = true; 474 | QString check = o->checkString(); 475 | if (check.isEmpty()) 476 | output = false; 477 | 478 | if (output) { 479 | printf("%s", check.toLatin1().data()); 480 | fflush(stdout); 481 | } 482 | 483 | first_debug = true; 484 | bool ok = o->exec(); 485 | o->success = ok; 486 | 487 | if (output) { 488 | QString result = o->resultString(); 489 | if (!first_debug) 490 | printf(" -> %s\n", result.toLatin1().data()); 491 | else 492 | printf(" %s\n", result.toLatin1().data()); 493 | } 494 | 495 | if (!ok && o->required) { 496 | printf("\nError: need %s!\n", o->name().toLatin1().data()); 497 | return false; 498 | } 499 | } 500 | return true; 501 | } 502 | 503 | QString Conf::qvar(const QString &s) { return vars.value(s); } 504 | 505 | QString Conf::normalizePath(const QString &s) const { return qc_normalize_path(s); } 506 | 507 | QString Conf::escapeQmakeVar(const QString &s) const { return qc_escape_string_var(s); } 508 | 509 | QString Conf::escapedIncludes() const { return qc_prepare_includepath(INCLUDEPATH); } 510 | 511 | QString Conf::escapedLibs() const { return qc_prepare_libs(LIBS); } 512 | 513 | QString Conf::expandIncludes(const QString &inc) { return QLatin1String("-I") + inc; } 514 | 515 | QString Conf::expandLibs(const QString &lib) { return QLatin1String("-L") + lib; } 516 | 517 | int Conf::doCommand(const QString &s, QByteArray *out) 518 | { 519 | debug(QString("[%1]").arg(s)); 520 | int r = qc_runcommand(s, out, debug_enabled); 521 | debug(QString("returned: %1").arg(r)); 522 | return r; 523 | } 524 | 525 | int Conf::doCommand(const QString &prog, const QStringList &args, QByteArray *out) 526 | { 527 | QString fullcmd = prog; 528 | QString argstr = args.join(QLatin1String(" ")); 529 | if (!argstr.isEmpty()) 530 | fullcmd += QString(" ") + argstr; 531 | debug(QString("[%1]").arg(fullcmd)); 532 | int r = qc_runprogram(prog, args, out, debug_enabled); 533 | debug(QString("returned: %1").arg(r)); 534 | return r; 535 | } 536 | 537 | bool Conf::doCompileAndLink(const QString &filedata, const QStringList &incs, const QString &libs, 538 | const QString &proextra, int *retcode) 539 | { 540 | #ifdef Q_OS_WIN 541 | QDir tmp("qconftemp"); 542 | #else 543 | QDir tmp(".qconftemp"); 544 | #endif 545 | QStringList normalizedLibs; 546 | foreach (const QString &l, qc_splitflags(libs)) { 547 | normalizedLibs.append(qc_normalize_path(l)); 548 | } 549 | 550 | if (!tmp.mkdir("atest")) { 551 | debug(QString("unable to create atest dir: %1").arg(tmp.absoluteFilePath("atest"))); 552 | return false; 553 | } 554 | QDir dir(tmp.filePath("atest")); 555 | if (!dir.exists()) { 556 | debug("atest dir does not exist"); 557 | return false; 558 | } 559 | 560 | QString fname = dir.filePath("atest.cpp"); 561 | QString out = "atest"; 562 | QFile f(fname); 563 | if (!f.open(QFile::WriteOnly | QFile::Truncate)) { 564 | debug("unable to open atest.cpp for writing"); 565 | return false; 566 | } 567 | if (f.write(filedata.toLatin1()) == -1) { 568 | debug("error writing to atest.cpp"); 569 | return false; 570 | } 571 | f.close(); 572 | 573 | debug(QString("Wrote atest.cpp:\n%1").arg(filedata)); 574 | 575 | QString pro = QString("CONFIG += console\n" 576 | "CONFIG -= qt app_bundle\n" 577 | "DESTDIR = $$PWD\n" 578 | "SOURCES += atest.cpp\n"); 579 | QString inc = qc_prepare_includepath(incs); 580 | if (!inc.isEmpty()) 581 | pro += "INCLUDEPATH += " + inc + '\n'; 582 | QString escaped_libs = qc_prepare_libs(normalizedLibs); 583 | if (!escaped_libs.isEmpty()) 584 | pro += "LIBS += " + escaped_libs + '\n'; 585 | pro += proextra; 586 | 587 | fname = dir.filePath("atest.pro"); 588 | f.setFileName(fname); 589 | if (!f.open(QFile::WriteOnly | QFile::Truncate)) { 590 | debug("unable to open atest.pro for writing"); 591 | return false; 592 | } 593 | if (f.write(pro.toLatin1()) == -1) { 594 | debug("error writing to atest.pro"); 595 | return false; 596 | } 597 | f.close(); 598 | 599 | debug(QString("Wrote atest.pro:\n%1").arg(pro)); 600 | 601 | QString oldpath = QDir::currentPath(); 602 | QDir::setCurrent(dir.path()); 603 | 604 | bool ok = false; 605 | int r = doCommand(qmake_path, QStringList() << "atest.pro"); 606 | if (r == 0) { 607 | r = doCommand(maketool, QStringList()); 608 | if (r == 0) { 609 | ok = true; 610 | if (retcode) { 611 | QString runatest = out; 612 | #ifdef Q_OS_UNIX 613 | runatest.prepend("./"); 614 | #endif 615 | *retcode = doCommand(runatest, QStringList()); 616 | } 617 | } 618 | r = doCommand(maketool, QStringList() << "distclean"); 619 | if (r != 0) 620 | debug("error during atest distclean"); 621 | } 622 | 623 | QDir::setCurrent(oldpath); 624 | 625 | // cleanup 626 | // dir.remove("atest.pro"); 627 | // dir.remove("atest.cpp"); 628 | // tmp.rmdir("atest"); 629 | 630 | // remove whole dir since distclean doesn't always work 631 | qc_removedir(tmp.filePath("atest")); 632 | 633 | if (!ok) 634 | return false; 635 | return true; 636 | } 637 | 638 | bool Conf::checkHeader(const QString &path, const QString &h) { return QDir(path).exists(h); } 639 | 640 | bool Conf::findHeader(const QString &h, const QStringList &ext, QString *inc) 641 | { 642 | if (checkHeader("/usr/include", h)) { 643 | *inc = ""; 644 | return true; 645 | } 646 | QStringList dirs; 647 | dirs += "/usr/local/include"; 648 | dirs += ext; 649 | 650 | QString prefix = qc_getenv("PREFIX"); 651 | if (!prefix.isEmpty()) { 652 | prefix += "/include"; 653 | prefix = qc_normalize_path(prefix); 654 | if (!dirs.contains(prefix)) 655 | dirs << prefix; 656 | } 657 | 658 | for (QStringList::ConstIterator it = dirs.begin(); it != dirs.end(); ++it) { 659 | if (checkHeader(*it, h)) { 660 | *inc = *it; 661 | return true; 662 | } 663 | } 664 | return false; 665 | } 666 | 667 | bool Conf::checkLibrary(const QString &path, const QString &name) 668 | { 669 | QString str = 670 | //"#include \n" 671 | "int main()\n" 672 | "{\n" 673 | //" printf(\"library checker running\\\\n\");\n" 674 | " return 0;\n" 675 | "}\n"; 676 | 677 | QString libs; 678 | if (!path.isEmpty()) 679 | libs += QString("-L") + path + ' '; 680 | libs += QString("-l") + name; 681 | if (!doCompileAndLink(str, QStringList(), libs, QString())) 682 | return false; 683 | return true; 684 | } 685 | 686 | bool Conf::findLibrary(const QString &name, QString *lib) 687 | { 688 | if (checkLibrary("", name)) { 689 | *lib = ""; 690 | return true; 691 | } 692 | if (checkLibrary("/usr/local/lib", name)) { 693 | *lib = "/usr/local/lib"; 694 | return true; 695 | } 696 | 697 | QString prefix = qc_getenv("PREFIX"); 698 | if (!prefix.isEmpty()) { 699 | prefix += "/lib"; 700 | prefix = qc_normalize_path(prefix); 701 | if (checkLibrary(prefix, name)) { 702 | *lib = prefix; 703 | return true; 704 | } 705 | } 706 | 707 | return false; 708 | } 709 | 710 | QString Conf::findProgram(const QString &prog) { return qc_findprogram(prog); } 711 | 712 | bool Conf::findSimpleLibrary(const QString &incvar, const QString &libvar, const QString &incname, 713 | const QString &libname, QString *incpath, QString *libs) 714 | { 715 | QString inc, lib; 716 | QString s; 717 | 718 | s = getenv(incvar).trimmed(); 719 | if (!s.isEmpty()) { 720 | if (!checkHeader(s, incname)) { 721 | if (debug_enabled) 722 | printf("%s is not found in \"%s\"\n", qPrintable(incname), qPrintable(s)); 723 | return false; 724 | } 725 | inc = s; 726 | } else { 727 | if (!findHeader(incname, QStringList(), &s)) { 728 | if (debug_enabled) 729 | printf("%s is not found anywhere\n", qPrintable(incname)); 730 | return false; 731 | } 732 | inc = s; 733 | } 734 | 735 | s = getenv(libvar).trimmed(); 736 | if (!s.isEmpty()) { 737 | if (!checkLibrary(s, libname)) { 738 | if (debug_enabled) 739 | printf("%s is not found in \"%s\"\n", qPrintable(libname), qPrintable(s)); 740 | return false; 741 | } 742 | lib = s; 743 | } else { 744 | if (!findLibrary(libname, &s)) { 745 | if (debug_enabled) 746 | printf("%s is not found anywhere\n", qPrintable(libname)); 747 | return false; 748 | } 749 | lib = s; 750 | } 751 | 752 | QString lib_out; 753 | if (!lib.isEmpty()) 754 | lib_out += QString("-L") + s + " "; 755 | lib_out += QString("-l") + libname; 756 | 757 | *incpath = inc; 758 | *libs = lib_out; 759 | return true; 760 | } 761 | 762 | bool Conf::findFooConfig(const QString &path, QString *version, QStringList *incs, QString *libs, QString *otherflags) 763 | { 764 | QStringList args; 765 | QByteArray out; 766 | int ret; 767 | 768 | args += "--version"; 769 | ret = doCommand(path, args, &out); 770 | if (ret != 0) 771 | return false; 772 | 773 | QString version_out = QString::fromLatin1(out).trimmed(); 774 | 775 | args.clear(); 776 | args += "--libs"; 777 | ret = doCommand(path, args, &out); 778 | if (ret != 0) 779 | return false; 780 | 781 | QString libs_out = QString::fromLatin1(out).trimmed(); 782 | 783 | args.clear(); 784 | args += "--cflags"; 785 | ret = doCommand(path, args, &out); 786 | if (ret != 0) 787 | return false; 788 | 789 | QString cflags = QString::fromLatin1(out).trimmed(); 790 | 791 | QStringList incs_out, otherflags_out; 792 | qc_splitcflags(cflags, &incs_out, &otherflags_out); 793 | 794 | *version = version_out; 795 | *incs = incs_out; 796 | *libs = libs_out; 797 | *otherflags = otherflags_out.join(QLatin1String(" ")); 798 | return true; 799 | } 800 | 801 | bool Conf::findPkgConfig(const QString &name, VersionMode mode, const QString &req_version, QString *version, 802 | QStringList *incs, QString *libs, QString *otherflags) 803 | { 804 | QStringList args; 805 | QByteArray out; 806 | int ret; 807 | 808 | args += name; 809 | args += "--exists"; 810 | ret = doCommand("pkg-config", args, &out); 811 | if (ret != 0) 812 | return false; 813 | 814 | if (mode != VersionAny) { 815 | args.clear(); 816 | args += name; 817 | if (mode == VersionMin) 818 | args += QString("--atleast-version=%1").arg(req_version); 819 | else if (mode == VersionMax) 820 | args += QString("--max-version=%1").arg(req_version); 821 | else 822 | args += QString("--exact-version=%1").arg(req_version); 823 | ret = doCommand("pkg-config", args, &out); 824 | if (ret != 0) 825 | return false; 826 | } 827 | 828 | args.clear(); 829 | args += name; 830 | args += "--modversion"; 831 | ret = doCommand("pkg-config", args, &out); 832 | if (ret != 0) 833 | return false; 834 | 835 | QString version_out = QString::fromLatin1(out).trimmed(); 836 | 837 | args.clear(); 838 | args += name; 839 | args += "--libs"; 840 | ret = doCommand("pkg-config", args, &out); 841 | if (ret != 0) 842 | return false; 843 | 844 | QString libs_out = QString::fromLatin1(out).trimmed(); 845 | 846 | args.clear(); 847 | args += name; 848 | args += "--cflags"; 849 | ret = doCommand("pkg-config", args, &out); 850 | if (ret != 0) 851 | return false; 852 | 853 | QString cflags = QString::fromLatin1(out).trimmed(); 854 | 855 | QStringList incs_out, otherflags_out; 856 | qc_splitcflags(cflags, &incs_out, &otherflags_out); 857 | 858 | *version = version_out; 859 | *incs = incs_out; 860 | *libs = libs_out; 861 | *otherflags = otherflags_out.join(QLatin1String(" ")); 862 | return true; 863 | } 864 | 865 | void Conf::addDefine(const QString &str) 866 | { 867 | if (DEFINES.isEmpty()) 868 | DEFINES = str; 869 | else 870 | DEFINES += QString(" ") + str; 871 | debug(QString("DEFINES += %1").arg(str)); 872 | } 873 | 874 | void Conf::addLib(const QString &str) 875 | { 876 | QStringList libs = qc_splitflags(str); 877 | foreach (const QString &lib, libs) { 878 | if (lib.startsWith("-l")) { 879 | LIBS.append(lib); 880 | } else { 881 | LIBS.append(qc_normalize_path(lib)); // we don't care about -L prefix since normalier does not touch it. 882 | } 883 | } 884 | debug(QString("LIBS += %1").arg(str)); 885 | } 886 | 887 | void Conf::addIncludePath(const QString &str) 888 | { 889 | INCLUDEPATH.append(qc_normalize_path(str)); 890 | debug(QString("INCLUDEPATH += %1").arg(str)); 891 | } 892 | 893 | void Conf::addExtra(const QString &str) 894 | { 895 | extra += str + '\n'; 896 | debug(QString("extra += %1").arg(str)); 897 | } 898 | 899 | //---------------------------------------------------------------------------- 900 | // main 901 | //---------------------------------------------------------------------------- 902 | #include "conf4.moc" 903 | 904 | #ifdef HAVE_MODULES 905 | #include "modules.cpp" 906 | #endif 907 | 908 | int main(int argc, char **argv) 909 | { 910 | QCoreApplication app(argc, argv); 911 | Conf * conf = new Conf; 912 | ConfObj * o = 0; 913 | Q_UNUSED(o); 914 | #ifdef HAVE_MODULES 915 | #include "modules_new.cpp" 916 | #endif 917 | 918 | conf->debug_enabled = (qc_getenv("QC_VERBOSE") == "Y") ? true : false; 919 | if (conf->debug_enabled) 920 | printf(" -> ok\n"); 921 | else 922 | printf("ok\n"); 923 | 924 | QString confCommand = qc_getenv("QC_COMMAND"); 925 | QString proName = qc_getenv("QC_PROFILE"); 926 | conf->qmake_path = qc_getenv("QC_QMAKE"); 927 | conf->qmakespec = qc_getenv("QC_QMAKESPEC"); 928 | conf->maketool = qc_getenv("QC_MAKETOOL"); 929 | 930 | if (conf->debug_enabled) 931 | printf("conf command: [%s]\n", qPrintable(confCommand)); 932 | 933 | QString confPath = qc_findself(confCommand); 934 | if (confPath.isEmpty()) { 935 | printf("Error: cannot find myself; rerun with an absolute path\n"); 936 | return 1; 937 | } 938 | 939 | QString srcdir = QFileInfo(confPath).absolutePath(); 940 | QString builddir = QDir::current().absolutePath(); 941 | QString proPath = QDir(srcdir).filePath(proName); 942 | 943 | if (conf->debug_enabled) { 944 | printf("conf path: [%s]\n", qPrintable(confPath)); 945 | printf("srcdir: [%s]\n", qPrintable(srcdir)); 946 | printf("builddir: [%s]\n", qPrintable(builddir)); 947 | printf("profile: [%s]\n", qPrintable(proPath)); 948 | printf("qmake path: [%s]\n", qPrintable(conf->qmake_path)); 949 | printf("qmakespec: [%s]\n", qPrintable(conf->qmakespec)); 950 | printf("make tool: [%s]\n", qPrintable(conf->maketool)); 951 | printf("\n"); 952 | } 953 | 954 | bool success = false; 955 | if (conf->exec()) { 956 | QFile f("conf.pri"); 957 | if (!f.open(QFile::WriteOnly | QFile::Truncate)) { 958 | printf("Error writing %s\n", qPrintable(f.fileName())); 959 | return 1; 960 | } 961 | 962 | QString str; 963 | str += "# qconf\n\n"; 964 | str += "greaterThan(QT_MAJOR_VERSION, 4):CONFIG += c++11\n"; 965 | 966 | QString var; 967 | var = qc_normalize_path(qc_getenv("PREFIX")); 968 | if (!var.isEmpty()) 969 | str += QString("PREFIX = %1\n").arg(var); 970 | var = qc_normalize_path(qc_getenv("BINDIR")); 971 | if (!var.isEmpty()) 972 | str += QString("BINDIR = %1\n").arg(var); 973 | var = qc_normalize_path(qc_getenv("INCDIR")); 974 | if (!var.isEmpty()) 975 | str += QString("INCDIR = %1\n").arg(var); 976 | var = qc_normalize_path(qc_getenv("LIBDIR")); 977 | if (!var.isEmpty()) 978 | str += QString("LIBDIR = %1\n").arg(var); 979 | var = qc_normalize_path(qc_getenv("DATADIR")); 980 | if (!var.isEmpty()) 981 | str += QString("DATADIR = %1\n").arg(var); 982 | str += '\n'; 983 | 984 | if (qc_getenv("QC_STATIC") == "Y") 985 | str += "CONFIG += staticlib\n"; 986 | 987 | // TODO: don't need this? 988 | // str += "QT_PATH_PLUGINS = " + QString(qInstallPathPlugins()) + '\n'; 989 | 990 | if (!conf->DEFINES.isEmpty()) 991 | str += "DEFINES += " + conf->DEFINES + '\n'; 992 | if (!conf->INCLUDEPATH.isEmpty()) 993 | str += "INCLUDEPATH += " + qc_prepare_includepath(conf->INCLUDEPATH) + '\n'; 994 | if (!conf->LIBS.isEmpty()) 995 | str += "LIBS += " + qc_prepare_libs(conf->LIBS) + '\n'; 996 | if (!conf->extra.isEmpty()) 997 | str += conf->extra; 998 | str += '\n'; 999 | 1000 | var = qc_getenv("QC_EXTRACONF"); 1001 | if (!var.isEmpty()) 1002 | str += ("\n# Extra conf from command line\n" + var + "\n"); 1003 | 1004 | QByteArray cs = str.toLatin1(); 1005 | f.write(cs); 1006 | f.close(); 1007 | success = true; 1008 | } 1009 | QString qmake_path = conf->qmake_path; 1010 | QString qmakespec = conf->qmakespec; 1011 | delete conf; 1012 | 1013 | if (!success) 1014 | return 1; 1015 | 1016 | // run qmake on the project file 1017 | QStringList args; 1018 | if (!qmakespec.isEmpty()) { 1019 | args += "-spec"; 1020 | args += qmakespec; 1021 | } 1022 | args += proPath; 1023 | int ret = qc_runprogram(qmake_path, args, 0, true); 1024 | if (ret != 0) 1025 | return 1; 1026 | 1027 | return 0; 1028 | } 1029 | -------------------------------------------------------------------------------- /configure: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # Generated by qconf 2.0 ( https://github.com/psi-plus/qconf ) 4 | # 5 | 6 | show_usage() { 7 | cat </dev/null` 38 | if echo $WHICH | grep 'shell built-in command' >/dev/null 2>&1; then 39 | WHICH=which 40 | elif [ -z "$WHICH" ]; then 41 | if which which >/dev/null 2>&1; then 42 | WHICH=which 43 | else 44 | for a in /usr/ucb /usr/bin /bin /usr/local/bin; do 45 | if [ -x $a/which ]; then 46 | WHICH=$a/which 47 | break 48 | fi 49 | done 50 | fi 51 | fi 52 | 53 | RET_CODE=1 54 | if [ -z "$WHICH" ]; then 55 | OLD_IFS=$IFS 56 | IFS=: 57 | for a in $PATH; do 58 | if [ -x $a/$1 ]; then 59 | echo "$a/$1" 60 | RET_CODE=0 61 | [ -z "$ALL_MATCHES" ] && break 62 | fi 63 | done 64 | IFS=$OLD_IFS 65 | export IFS 66 | else 67 | a=`"$WHICH" "$ALL_MATCHES" "$1" 2>/dev/null` 68 | if [ ! -z "$a" -a -x "$a" ]; then 69 | echo "$a" 70 | RET_CODE=0 71 | fi 72 | fi 73 | HOME=$OLD_HOME 74 | export HOME 75 | return $RET_CODE 76 | } 77 | WHICH=which_command 78 | 79 | # find a make command 80 | if [ -z "$MAKE" ]; then 81 | MAKE= 82 | for mk in gmake make; do 83 | if $WHICH $mk >/dev/null 2>&1; then 84 | MAKE=`$WHICH $mk` 85 | break 86 | fi 87 | done 88 | if [ -z "$MAKE" ]; then 89 | echo "You don't seem to have 'make' or 'gmake' in your PATH." 90 | echo "Cannot proceed." 91 | exit 1 92 | fi 93 | fi 94 | 95 | show_qt_info() { 96 | printf "Be sure you have a proper Qt 4.0+ build environment set up. This means not\n" 97 | printf "just Qt, but also a C++ compiler, a make tool, and any other packages\n" 98 | printf "necessary for compiling C++ programs.\n" 99 | printf "\n" 100 | printf "If you are certain everything is installed, then it could be that Qt is not\n" 101 | printf "being recognized or that a different version of Qt is being detected by\n" 102 | printf "mistake (for example, this could happen if \$QTDIR is pointing to a Qt 3\n" 103 | printf "installation). At least one of the following conditions must be satisfied:\n" 104 | printf "\n" 105 | printf " 1) --qtdir is set to the location of Qt\n" 106 | printf " 2) \$QTDIR is set to the location of Qt\n" 107 | printf " 3) QtCore is in the pkg-config database\n" 108 | printf " 4) qmake is in the \$PATH\n" 109 | printf "\n" 110 | printf "This script will use the first one it finds to be true, checked in the above\n" 111 | printf "order. #3 and #4 are the recommended options. #1 and #2 are mainly for\n" 112 | printf "overriding the system configuration.\n" 113 | printf "\n" 114 | } 115 | 116 | while [ $# -gt 0 ]; do 117 | optarg=`expr "x$1" : 'x[^=]*=\(.*\)'` 118 | case "$1" in 119 | --prefix=*) 120 | PREFIX=$optarg 121 | shift 122 | ;; 123 | 124 | --bindir=*) 125 | BINDIR=$optarg 126 | shift 127 | ;; 128 | 129 | --datadir=*) 130 | DATADIR=$optarg 131 | shift 132 | ;; 133 | 134 | --qtdir=*) 135 | EX_QTDIR=$optarg 136 | shift 137 | ;; 138 | 139 | --extraconf=*) 140 | QC_EXTRACONF=$optarg 141 | shift 142 | ;; 143 | 144 | --verbose) 145 | QC_VERBOSE="Y" 146 | shift 147 | ;; 148 | --qtselect=*) 149 | QC_QTSELECT="${optarg}" 150 | shift 151 | ;; 152 | --help) show_usage; exit ;; 153 | *) echo "configure: WARNING: unrecognized options: $1" >&2; shift; ;; 154 | esac 155 | done 156 | 157 | PREFIX=${PREFIX:-/usr/local} 158 | BINDIR=${BINDIR:-$PREFIX/bin} 159 | DATADIR=${DATADIR:-$PREFIX/share} 160 | 161 | echo "Configuring QConf ..." 162 | 163 | if [ "$QC_VERBOSE" = "Y" ]; then 164 | echo 165 | echo PREFIX=$PREFIX 166 | echo BINDIR=$BINDIR 167 | echo DATADIR=$DATADIR 168 | echo EX_QTDIR=$EX_QTDIR 169 | echo QC_EXTRACONF=$QC_EXTRACONF 170 | echo 171 | fi 172 | 173 | printf "Verifying Qt build environment ... " 174 | 175 | if [ -z "$QC_QTSELECT" ]; then 176 | QC_QTSELECT="$(echo $QT_SELECT | tr -d "qt")" 177 | fi 178 | 179 | if [ ! -z "$QC_QTSELECT" ]; then 180 | QTSEARCHTEXT="$QC_QTSELECT" 181 | else 182 | QTSEARCHTEXT="4 or 5" 183 | fi 184 | 185 | # run qmake and check version 186 | qmake_check() { 187 | if [ -x "$1" ]; then 188 | cmd="\"$1\" -query QT_VERSION" 189 | if [ "$QC_VERBOSE" = "Y" ]; then 190 | echo "running: $cmd" 191 | fi 192 | vout=`/bin/sh -c "$cmd" 2>&1` 193 | case "${vout}" in 194 | *.*.*) 195 | vmaj="${vout%%.*}" 196 | if [ ! -z "$QC_QTSELECT" ]; then 197 | if [ "$vmaj" = "$QC_QTSELECT" ]; then 198 | return 0 199 | fi 200 | else 201 | if [ "$vmaj" = "4" ] || [ "$vmaj" = "5" ]; then 202 | return 0 203 | fi 204 | fi 205 | ;; 206 | esac 207 | if [ "$QC_VERBOSE" = "Y" ]; then 208 | echo "Warning: $1 not for Qt ${QTSEARCHTEXT}" 209 | fi 210 | fi 211 | return 1 212 | } 213 | 214 | if [ "$QC_VERBOSE" = "Y" ]; then 215 | echo 216 | fi 217 | 218 | qm="" 219 | qt4_names="qmake-qt4 qmake4" 220 | qt5_names="qmake-qt5 qmake5" 221 | names="qmake" 222 | if [ -z "$QC_QTSELECT" ]; then 223 | names="${qt5_names} ${qt4_names} $names" 224 | else 225 | if [ "$QC_QTSELECT" = "4" ]; then 226 | names="${qt4_names} $names" 227 | elif [ "$QC_QTSELECT" -ge "5" ]; then 228 | names="${qt5_names} $names" 229 | fi 230 | fi 231 | 232 | if [ -z "$qm" ] && [ ! -z "$EX_QTDIR" ]; then 233 | # qt4 check: --qtdir 234 | for n in $names; do 235 | qstr=$EX_QTDIR/bin/$n 236 | if qmake_check "$qstr"; then 237 | qm=$qstr 238 | break 239 | fi 240 | done 241 | if [ -z "$qm" ] && [ "$QC_VERBOSE" = "Y" ]; then 242 | echo "Warning: qmake not found via --qtdir" 243 | fi 244 | 245 | elif [ -z "$qm" ] && [ ! -z "$QTDIR" ]; then 246 | # qt4 check: QTDIR 247 | for n in $names; do 248 | qstr=$QTDIR/bin/$n 249 | if qmake_check "$qstr"; then 250 | qm=$qstr 251 | break 252 | fi 253 | done 254 | if [ -z "$qm" ] && [ "$QC_VERBOSE" = "Y" ]; then 255 | echo "Warning: qmake not found via \$QTDIR" 256 | fi 257 | 258 | else 259 | # Try all other implicit checks 260 | 261 | # qtchooser 262 | if [ -z "$qm" ]; then 263 | qtchooser=$($WHICH qtchooser 2>/dev/null) 264 | if [ ! -z "$qtchooser" ]; then 265 | if [ ! -z "$QC_QTSELECT" ]; then 266 | versions="$QC_QTSELECT" 267 | else 268 | cmd="$qtchooser --list-versions" 269 | if [ "$QC_VERBOSE" = "Y" ]; then 270 | echo "running: $cmd" 271 | fi 272 | versions=`$cmd` 273 | fi 274 | for version in $versions; do 275 | cmd="$qtchooser -run-tool=qmake -qt=${version} -query QT_INSTALL_BINS" 276 | if [ "$QC_VERBOSE" = "Y" ]; then 277 | echo "running: $cmd" 278 | fi 279 | qtbins=`$cmd 2>/dev/null` 280 | if [ ! -z "$qtbins" ] && qmake_check "$qtbins/qmake"; then 281 | qm="$qtbins/qmake" 282 | break 283 | fi 284 | done 285 | fi 286 | fi 287 | if [ -z "$qm" ] && [ "$QC_VERBOSE" = "Y" ]; then 288 | echo "Warning: qmake not found via qtchooser" 289 | fi 290 | 291 | # qt4: pkg-config 292 | if [ -z "$qm" ]; then 293 | cmd="pkg-config QtCore --variable=exec_prefix" 294 | if [ "$QC_VERBOSE" = "Y" ]; then 295 | echo "running: $cmd" 296 | fi 297 | str=`$cmd 2>/dev/null` 298 | if [ ! -z "$str" ]; then 299 | for n in $names; do 300 | qstr=$str/bin/$n 301 | if qmake_check "$qstr"; then 302 | qm=$qstr 303 | break 304 | fi 305 | done 306 | fi 307 | fi 308 | if [ -z "$qm" ] && [ "$QC_VERBOSE" = "Y" ]; then 309 | echo "Warning: qmake not found via pkg-config" 310 | fi 311 | 312 | # qmake in PATH 313 | if [ -z "$qm" ]; then 314 | for n in $names; do 315 | qstr=`$WHICH -a $n 2>/dev/null` 316 | for q in $qstr; do 317 | if qmake_check "$q"; then 318 | qm="$q" 319 | break 320 | fi 321 | done 322 | if [ ! -z "$qm" ]; then 323 | break 324 | fi 325 | done 326 | fi 327 | if [ -z "$qm" ] && [ "$QC_VERBOSE" = "Y" ]; then 328 | echo "Warning: qmake not found via \$PATH" 329 | fi 330 | 331 | # end of implicit checks 332 | fi 333 | 334 | if [ -z "$qm" ]; then 335 | if [ "$QC_VERBOSE" = "Y" ]; then 336 | echo " -> fail" 337 | else 338 | echo "fail" 339 | fi 340 | printf "\n" 341 | printf "Reason: Unable to find the 'qmake' tool for Qt ${QTSEARCHTEXT}.\n" 342 | printf "\n" 343 | show_qt_info 344 | exit 1; 345 | fi 346 | if [ "$QC_VERBOSE" = "Y" ]; then 347 | echo qmake found in "$qm" 348 | fi 349 | 350 | # try to determine the active makespec 351 | defmakespec=$QMAKESPEC 352 | if [ -z "$defmakespec" ]; then 353 | if $WHICH readlink >/dev/null 2>&1; then 354 | READLINK=`$WHICH readlink` 355 | fi 356 | if [ ! -z "$READLINK" ]; then 357 | qt_mkspecsdir=`"$qm" -query QT_INSTALL_DATA`/mkspecs 358 | if [ -d "$qt_mkspecsdir" ] && [ -h "$qt_mkspecsdir/default" ]; then 359 | defmakespec=`$READLINK $qt_mkspecsdir/default` 360 | fi 361 | fi 362 | fi 363 | 364 | if [ "$QC_VERBOSE" = "Y" ]; then 365 | echo makespec is $defmakespec 366 | fi 367 | 368 | qm_spec="" 369 | # if the makespec is macx-xcode, force macx-g++ 370 | if [ "$defmakespec" = "macx-xcode" ]; then 371 | qm_spec=macx-g++ 372 | QMAKESPEC=$qm_spec 373 | export QMAKESPEC 374 | if [ "$QC_VERBOSE" = "Y" ]; then 375 | echo overriding makespec to $qm_spec 376 | fi 377 | fi 378 | 379 | gen_files() { 380 | cat >"$1/modules.cpp" <"$1/modules_new.cpp" <"$1/conf4.h" < 399 | 400 | class Conf; 401 | 402 | enum VersionMode { VersionMin, VersionExact, VersionMax, VersionAny }; 403 | 404 | // ConfObj 405 | // 406 | // Subclass ConfObj to create a new configuration module. 407 | class ConfObj { 408 | public: 409 | Conf *conf; 410 | bool required; 411 | bool disabled; 412 | bool success; 413 | 414 | ConfObj(Conf *c); 415 | virtual ~ConfObj(); 416 | 417 | // long or descriptive name of what is being checked/performed 418 | // example: "KDE >= 3.3" 419 | virtual QString name() const = 0; 420 | 421 | // short name 422 | // example: "kde" 423 | virtual QString shortname() const = 0; 424 | 425 | // string to display during check 426 | // default: "Checking for [name] ..." 427 | virtual QString checkString() const; 428 | 429 | // string to display after check 430 | // default: "yes" or "no", based on result of exec() 431 | virtual QString resultString() const; 432 | 433 | // this is where the checking code goes 434 | virtual bool exec() = 0; 435 | }; 436 | 437 | // Conf 438 | // 439 | // Interact with this class from your ConfObj to perform detection 440 | // operations and to output configuration parameters. 441 | class Conf { 442 | public: 443 | bool debug_enabled; 444 | QString qmake_path; 445 | QString qmakespec; 446 | QString maketool; 447 | 448 | QString DEFINES; 449 | QStringList INCLUDEPATH; 450 | QStringList LIBS; 451 | QString extra; 452 | 453 | QList list; 454 | QMap vars; 455 | 456 | Conf(); 457 | ~Conf(); 458 | 459 | QString getenv(const QString &var); 460 | QString qvar(const QString &s); 461 | QString normalizePath(const QString &s) const; 462 | QString escapeQmakeVar(const QString &s) const; 463 | inline QString escapePath(const QString &s) /* prepare fs path for qmake file */ 464 | { 465 | return escapeQmakeVar(normalizePath(s)); 466 | } 467 | QString escapedIncludes() const; 468 | QString escapedLibs() const; 469 | 470 | bool exec(); 471 | 472 | void debug(const QString &s); 473 | 474 | QString expandIncludes(const QString &inc); 475 | QString expandLibs(const QString &lib); 476 | 477 | int doCommand(const QString &s, QByteArray *out = 0); 478 | int doCommand(const QString &prog, const QStringList &args, QByteArray *out = 0); 479 | 480 | bool doCompileAndLink(const QString &filedata, const QStringList &incs, const QString &libs, 481 | const QString &proextra, int *retcode = 0); 482 | bool checkHeader(const QString &path, const QString &h); 483 | bool findHeader(const QString &h, const QStringList &ext, QString *inc); 484 | bool checkLibrary(const QString &path, const QString &name); 485 | bool findLibrary(const QString &name, QString *lib); 486 | QString findProgram(const QString &prog); 487 | bool findSimpleLibrary(const QString &incvar, const QString &libvar, const QString &incname, const QString &libname, 488 | QString *incpath, QString *libs); 489 | bool findFooConfig(const QString &path, QString *version, QStringList *incs, QString *libs, QString *otherflags); 490 | bool findPkgConfig(const QString &name, VersionMode mode, const QString &req_version, QString *version, 491 | QStringList *incs, QString *libs, QString *otherflags); 492 | 493 | void addDefine(const QString &str); 494 | void addLib(const QString &str); 495 | void addIncludePath(const QString &str); 496 | void addExtra(const QString &str); 497 | 498 | private: 499 | bool first_debug; 500 | 501 | friend class ConfObj; 502 | void added(ConfObj *o); 503 | }; 504 | 505 | #endif 506 | 507 | EOT 508 | cat >"$1/conf4.cpp" < 520 | #include 521 | #include 522 | #ifndef PATH_MAX 523 | #ifdef Q_OS_WIN 524 | #define PATH_MAX 260 525 | #endif 526 | #endif 527 | 528 | class MocTestObject : public QObject { 529 | 530 | Q_OBJECT 531 | public: 532 | MocTestObject() {} 533 | }; 534 | 535 | QString qc_getenv(const QString &var) 536 | { 537 | char *p = ::getenv(var.toLatin1().data()); 538 | if (!p) 539 | return QString(); 540 | return QString(p); 541 | } 542 | 543 | QStringList qc_pathlist() 544 | { 545 | QStringList list; 546 | QString path = qc_getenv("PATH"); 547 | if (!path.isEmpty()) { 548 | #if QT_VERSION >= 0x060000 549 | Qt::SplitBehavior flags = Qt::SkipEmptyParts; 550 | #else 551 | QString::SplitBehavior flags = QString::SkipEmptyParts; 552 | #endif 553 | #ifdef Q_OS_WIN 554 | list = path.split(';', flags); 555 | #else 556 | list = path.split(':', flags); 557 | #endif 558 | } 559 | #ifdef Q_OS_WIN 560 | list.prepend("."); 561 | #endif 562 | return list; 563 | } 564 | 565 | QString qc_findprogram(const QString &prog) 566 | { 567 | QString out; 568 | QStringList list = qc_pathlist(); 569 | for (int n = 0; n < list.count(); ++n) { 570 | QFileInfo fi(list[n] + '/' + prog); 571 | if (fi.exists() && fi.isExecutable()) { 572 | out = fi.filePath(); 573 | break; 574 | } 575 | 576 | #ifdef Q_OS_WIN 577 | // on windows, be sure to look for .exe 578 | if (prog.right(4).toLower() != ".exe") { 579 | fi = QFileInfo(list[n] + '/' + prog + ".exe"); 580 | if (fi.exists() && fi.isExecutable()) { 581 | out = fi.filePath(); 582 | break; 583 | } 584 | } 585 | #endif 586 | } 587 | return out; 588 | } 589 | 590 | QString qc_findself(const QString &argv0) 591 | { 592 | #ifdef Q_OS_WIN 593 | if (argv0.contains('\\\\')) 594 | #else 595 | if (argv0.contains('/')) 596 | #endif 597 | return argv0; 598 | else 599 | return qc_findprogram(argv0); 600 | } 601 | 602 | int qc_run_program_or_command(const QString &prog, const QStringList &args, const QString &command, QByteArray *out, 603 | bool showOutput) 604 | { 605 | if (out) 606 | out->clear(); 607 | 608 | QProcess process; 609 | process.setReadChannel(QProcess::StandardOutput); 610 | 611 | if (!prog.isEmpty()) 612 | process.start(prog, args); 613 | else if (!command.isEmpty()) 614 | process.start(command); 615 | else 616 | return -1; 617 | 618 | if (!process.waitForStarted(-1)) 619 | return -1; 620 | 621 | QByteArray buf; 622 | 623 | while (process.waitForReadyRead(-1)) { 624 | buf = process.readAllStandardOutput(); 625 | if (out) 626 | out->append(buf); 627 | if (showOutput) 628 | fprintf(stdout, "%s", buf.data()); 629 | 630 | buf = process.readAllStandardError(); 631 | if (showOutput) 632 | fprintf(stderr, "%s", buf.data()); 633 | } 634 | 635 | buf = process.readAllStandardError(); 636 | if (showOutput) 637 | fprintf(stderr, "%s", buf.data()); 638 | 639 | // calling waitForReadyRead will cause the process to eventually be 640 | // marked as finished, so we should not need to separately call 641 | // waitForFinished. however, we will do it anyway just to be safe. 642 | // we won't check the return value since false could still mean 643 | // success (if the process had already been marked as finished). 644 | process.waitForFinished(-1); 645 | 646 | if (process.exitStatus() != QProcess::NormalExit) 647 | return -1; 648 | 649 | return process.exitCode(); 650 | } 651 | 652 | int qc_runcommand(const QString &command, QByteArray *out, bool showOutput) 653 | { 654 | return qc_run_program_or_command(QString(), QStringList(), command, out, showOutput); 655 | } 656 | 657 | int qc_runprogram(const QString &prog, const QStringList &args, QByteArray *out, bool showOutput) 658 | { 659 | return qc_run_program_or_command(prog, args, QString(), out, showOutput); 660 | } 661 | 662 | bool qc_removedir(const QString &dirPath) 663 | { 664 | QDir dir(dirPath); 665 | if (!dir.exists()) 666 | return false; 667 | QStringList list = dir.entryList(); 668 | foreach (QString s, list) { 669 | if (s == "." || s == "..") 670 | continue; 671 | QFileInfo fi(dir.filePath(s)); 672 | if (fi.isDir()) { 673 | if (!qc_removedir(fi.filePath())) 674 | return false; 675 | } else { 676 | if (!dir.remove(s)) 677 | return false; 678 | } 679 | } 680 | QString dirName = dir.dirName(); 681 | if (!dir.cdUp()) 682 | return false; 683 | if (!dir.rmdir(dirName)) 684 | return false; 685 | return true; 686 | } 687 | 688 | // simple command line arguemnts splitter able to understand quoted args. 689 | // the splitter removes quotes and unescapes symbols as well. 690 | QStringList qc_splitflags(const QString &flags) 691 | { 692 | QStringList ret; 693 | bool searchStart = true; 694 | bool inQuotes = false; 695 | bool escaped = false; 696 | QChar quote, backslash = QLatin1Char('\\\\'); 697 | QString buf; 698 | #ifdef PATH_MAX 699 | buf.reserve(PATH_MAX); 700 | #endif 701 | for (int i = 0; i < flags.length(); i++) { 702 | if (searchStart && flags[i].isSpace()) { 703 | continue; 704 | } 705 | if (searchStart) { 706 | searchStart = false; 707 | buf.clear(); 708 | } 709 | if (escaped) { 710 | buf += flags[i]; 711 | escaped = false; 712 | continue; 713 | } 714 | // buf += flags[i]; 715 | if (inQuotes) { 716 | if (quote == QLatin1Char('\\'')) { 717 | if (flags[i] == quote) { 718 | inQuotes = false; 719 | continue; 720 | } 721 | } else { // we are in double quoetes 722 | if (i < flags.length() - 1 && flags[i] == backslash 723 | && (flags[i + 1] == QLatin1Char('"') || flags[i + 1] == backslash)) { 724 | // if next symbol is one of in parentheses ("\\) 725 | escaped = true; 726 | continue; 727 | } 728 | } 729 | } else { 730 | if (flags[i].isSpace()) { 731 | ret.append(buf); 732 | searchStart = true; 733 | buf.clear(); 734 | continue; 735 | #ifndef Q_OS_WIN /* on windows backslash is just a path separator */ 736 | } else if (flags[i] == backslash) { 737 | escaped = true; 738 | continue; // just add next symbol 739 | #endif 740 | } else if (flags[i] == QLatin1Char('\\'') || flags[i] == QLatin1Char('"')) { 741 | inQuotes = true; 742 | quote = flags[i]; 743 | continue; 744 | } 745 | } 746 | buf += flags[i]; 747 | } 748 | if (buf.size()) { 749 | ret.append(buf); 750 | } 751 | return ret; 752 | } 753 | 754 | void qc_splitcflags(const QString &cflags, QStringList *incs, QStringList *otherflags) 755 | { 756 | incs->clear(); 757 | otherflags->clear(); 758 | 759 | QStringList cflagsList = qc_splitflags(cflags); 760 | for (int n = 0; n < cflagsList.count(); ++n) { 761 | QString str = cflagsList[n]; 762 | if (str.startsWith("-I")) { 763 | // we want everything except the leading "-I" 764 | incs->append(str.remove(0, 2)); 765 | } else { 766 | // we want whatever is left 767 | otherflags->append(str); 768 | } 769 | } 770 | } 771 | 772 | QString qc_escapeArg(const QString &str) 773 | { 774 | QString out; 775 | for (int n = 0; n < (int)str.length(); ++n) { 776 | if (str[n] == '-') 777 | out += '_'; 778 | else 779 | out += str[n]; 780 | } 781 | return out; 782 | } 783 | 784 | QString qc_trim_char(const QString &s, const QChar &ch) 785 | { 786 | if (s.startsWith(ch) && s.endsWith(ch)) { 787 | return s.mid(1, s.size() - 2); 788 | } 789 | return s; 790 | } 791 | 792 | // removes surrounding quotes, removes trailing slashes, converts to native separators. 793 | // accepts unescaped but possible quoted path 794 | QString qc_normalize_path(const QString &str) 795 | { 796 | QString path = str.trimmed(); 797 | path = qc_trim_char(path, QLatin1Char('"')); 798 | path = qc_trim_char(path, QLatin1Char('\\'')); 799 | 800 | // It's OK to use unix style'/' paths on windows Qt handles this without any problems. 801 | // Using Windows-style '\\\\' can leads strange compilation error with MSYS which uses 802 | // unix style. 803 | QLatin1Char nativeSep('/'); 804 | #ifdef Q_OS_WIN 805 | path.replace(QLatin1Char('\\\\'), QLatin1Char('/')); 806 | #endif 807 | // trim trailing slashes 808 | while (path.length() && path[path.length() - 1] == nativeSep) { 809 | path.resize(path.length() - 1); 810 | } 811 | return path; 812 | } 813 | 814 | // escape filesystem path to be added to qmake pro/pri file. 815 | QString qc_escape_string_var(const QString &str) 816 | { 817 | QString path = str; 818 | path.replace(QLatin1Char('\\\\'), QLatin1String("\\\\\\\\")).replace(QLatin1Char('"'), QLatin1String("\\\\\\"")); 819 | if (path.indexOf(QLatin1Char(' ')) != -1) { // has spaces 820 | return QLatin1Char('"') + path + QLatin1Char('"'); 821 | } 822 | return path; 823 | } 824 | 825 | // escapes each path in incs and join into single string suiable for INCLUDEPATH var 826 | QString qc_prepare_includepath(const QStringList &incs) 827 | { 828 | if (incs.empty()) { 829 | return QString(); 830 | } 831 | QStringList ret; 832 | foreach (const QString &path, incs) { 833 | ret.append(qc_escape_string_var(path)); 834 | } 835 | return ret.join(QLatin1String(" ")); 836 | } 837 | 838 | // escapes each path in libs and to make it suiable for LIBS var 839 | // notice, entries of libs are every single arg for linker. 840 | QString qc_prepare_libs(const QStringList &libs) 841 | { 842 | if (libs.isEmpty()) { 843 | return QString(); 844 | } 845 | QSet pathSet; 846 | QStringList paths; 847 | QStringList ordered; 848 | foreach (const QString &arg, libs) { 849 | if (arg.startsWith(QLatin1String("-L"))) { 850 | QString path = qc_escape_string_var(arg.mid(2)); 851 | if (!pathSet.contains(path)) { 852 | pathSet.insert(path); 853 | paths.append(path); 854 | } 855 | } else if (arg.startsWith(QLatin1String("-l"))) { 856 | ordered.append(arg); 857 | } else { 858 | ordered.append(qc_escape_string_var(arg)); 859 | } 860 | } 861 | QString ret; 862 | if (paths.size()) { 863 | ret += (QLatin1String(" -L") + paths.join(QLatin1String(" -L")) + QLatin1Char(' ')); 864 | } 865 | return ret + ordered.join(QLatin1String(" ")); 866 | } 867 | 868 | //---------------------------------------------------------------------------- 869 | // ConfObj 870 | //---------------------------------------------------------------------------- 871 | ConfObj::ConfObj(Conf *c) 872 | { 873 | conf = c; 874 | conf->added(this); 875 | required = false; 876 | disabled = false; 877 | success = false; 878 | } 879 | 880 | ConfObj::~ConfObj() {} 881 | 882 | QString ConfObj::checkString() const { return QString("Checking for %1 ...").arg(name()); } 883 | 884 | QString ConfObj::resultString() const 885 | { 886 | if (success) 887 | return "yes"; 888 | else 889 | return "no"; 890 | } 891 | 892 | //---------------------------------------------------------------------------- 893 | // qc_internal_pkgconfig 894 | //---------------------------------------------------------------------------- 895 | class qc_internal_pkgconfig : public ConfObj { 896 | public: 897 | QString pkgname, desc; 898 | VersionMode mode; 899 | QString req_ver; 900 | 901 | qc_internal_pkgconfig(Conf *c, const QString &_name, const QString &_desc, VersionMode _mode, 902 | const QString &_req_ver) : 903 | ConfObj(c), 904 | pkgname(_name), desc(_desc), mode(_mode), req_ver(_req_ver) 905 | { 906 | } 907 | 908 | QString name() const { return desc; } 909 | QString shortname() const { return pkgname; } 910 | 911 | bool exec() 912 | { 913 | QStringList incs; 914 | QString version, libs, other; 915 | if (!conf->findPkgConfig(pkgname, mode, req_ver, &version, &incs, &libs, &other)) 916 | return false; 917 | 918 | for (int n = 0; n < incs.count(); ++n) 919 | conf->addIncludePath(incs[n]); 920 | if (!libs.isEmpty()) 921 | conf->addLib(libs); 922 | // if(!other.isEmpty()) 923 | // conf->addExtra(QString("QMAKE_CFLAGS += %1\\n").arg(other)); 924 | 925 | if (!required) 926 | conf->addDefine("HAVE_PKG_" + qc_escapeArg(pkgname).toUpper()); 927 | 928 | return true; 929 | } 930 | }; 931 | 932 | //---------------------------------------------------------------------------- 933 | // Conf 934 | //---------------------------------------------------------------------------- 935 | Conf::Conf() 936 | { 937 | // TODO: no more vars? 938 | // vars.insert("QMAKE_INCDIR_X11", new QString(X11_INC)); 939 | // vars.insert("QMAKE_LIBDIR_X11", new QString(X11_LIBDIR)); 940 | // vars.insert("QMAKE_LIBS_X11", new QString(X11_LIB)); 941 | // vars.insert("QMAKE_CC", CC); 942 | 943 | debug_enabled = false; 944 | first_debug = true; 945 | } 946 | 947 | Conf::~Conf() { qDeleteAll(list); } 948 | 949 | void Conf::added(ConfObj *o) { list.append(o); } 950 | 951 | QString Conf::getenv(const QString &var) { return qc_getenv(var); } 952 | 953 | void Conf::debug(const QString &s) 954 | { 955 | if (debug_enabled) { 956 | if (first_debug) 957 | printf("\\n"); 958 | first_debug = false; 959 | printf(" * %s\\n", qPrintable(s)); 960 | } 961 | } 962 | 963 | bool Conf::exec() 964 | { 965 | for (int n = 0; n < list.count(); ++n) { 966 | ConfObj *o = list[n]; 967 | 968 | // if this was a disabled-by-default option, check if it was enabled 969 | if (o->disabled) { 970 | QString v = QString("QC_ENABLE_") + qc_escapeArg(o->shortname()); 971 | if (getenv(v) != "Y") 972 | continue; 973 | } 974 | // and the opposite? 975 | else { 976 | QString v = QString("QC_DISABLE_") + qc_escapeArg(o->shortname()); 977 | if (getenv(v) == "Y") 978 | continue; 979 | } 980 | 981 | bool output = true; 982 | QString check = o->checkString(); 983 | if (check.isEmpty()) 984 | output = false; 985 | 986 | if (output) { 987 | printf("%s", check.toLatin1().data()); 988 | fflush(stdout); 989 | } 990 | 991 | first_debug = true; 992 | bool ok = o->exec(); 993 | o->success = ok; 994 | 995 | if (output) { 996 | QString result = o->resultString(); 997 | if (!first_debug) 998 | printf(" -> %s\\n", result.toLatin1().data()); 999 | else 1000 | printf(" %s\\n", result.toLatin1().data()); 1001 | } 1002 | 1003 | if (!ok && o->required) { 1004 | printf("\\nError: need %s!\\n", o->name().toLatin1().data()); 1005 | return false; 1006 | } 1007 | } 1008 | return true; 1009 | } 1010 | 1011 | QString Conf::qvar(const QString &s) { return vars.value(s); } 1012 | 1013 | QString Conf::normalizePath(const QString &s) const { return qc_normalize_path(s); } 1014 | 1015 | QString Conf::escapeQmakeVar(const QString &s) const { return qc_escape_string_var(s); } 1016 | 1017 | QString Conf::escapedIncludes() const { return qc_prepare_includepath(INCLUDEPATH); } 1018 | 1019 | QString Conf::escapedLibs() const { return qc_prepare_libs(LIBS); } 1020 | 1021 | QString Conf::expandIncludes(const QString &inc) { return QLatin1String("-I") + inc; } 1022 | 1023 | QString Conf::expandLibs(const QString &lib) { return QLatin1String("-L") + lib; } 1024 | 1025 | int Conf::doCommand(const QString &s, QByteArray *out) 1026 | { 1027 | debug(QString("[%1]").arg(s)); 1028 | int r = qc_runcommand(s, out, debug_enabled); 1029 | debug(QString("returned: %1").arg(r)); 1030 | return r; 1031 | } 1032 | 1033 | int Conf::doCommand(const QString &prog, const QStringList &args, QByteArray *out) 1034 | { 1035 | QString fullcmd = prog; 1036 | QString argstr = args.join(QLatin1String(" ")); 1037 | if (!argstr.isEmpty()) 1038 | fullcmd += QString(" ") + argstr; 1039 | debug(QString("[%1]").arg(fullcmd)); 1040 | int r = qc_runprogram(prog, args, out, debug_enabled); 1041 | debug(QString("returned: %1").arg(r)); 1042 | return r; 1043 | } 1044 | 1045 | bool Conf::doCompileAndLink(const QString &filedata, const QStringList &incs, const QString &libs, 1046 | const QString &proextra, int *retcode) 1047 | { 1048 | #ifdef Q_OS_WIN 1049 | QDir tmp("qconftemp"); 1050 | #else 1051 | QDir tmp(".qconftemp"); 1052 | #endif 1053 | QStringList normalizedLibs; 1054 | foreach (const QString &l, qc_splitflags(libs)) { 1055 | normalizedLibs.append(qc_normalize_path(l)); 1056 | } 1057 | 1058 | if (!tmp.mkdir("atest")) { 1059 | debug(QString("unable to create atest dir: %1").arg(tmp.absoluteFilePath("atest"))); 1060 | return false; 1061 | } 1062 | QDir dir(tmp.filePath("atest")); 1063 | if (!dir.exists()) { 1064 | debug("atest dir does not exist"); 1065 | return false; 1066 | } 1067 | 1068 | QString fname = dir.filePath("atest.cpp"); 1069 | QString out = "atest"; 1070 | QFile f(fname); 1071 | if (!f.open(QFile::WriteOnly | QFile::Truncate)) { 1072 | debug("unable to open atest.cpp for writing"); 1073 | return false; 1074 | } 1075 | if (f.write(filedata.toLatin1()) == -1) { 1076 | debug("error writing to atest.cpp"); 1077 | return false; 1078 | } 1079 | f.close(); 1080 | 1081 | debug(QString("Wrote atest.cpp:\\n%1").arg(filedata)); 1082 | 1083 | QString pro = QString("CONFIG += console\\n" 1084 | "CONFIG -= qt app_bundle\\n" 1085 | "DESTDIR = \$\$PWD\\n" 1086 | "SOURCES += atest.cpp\\n"); 1087 | QString inc = qc_prepare_includepath(incs); 1088 | if (!inc.isEmpty()) 1089 | pro += "INCLUDEPATH += " + inc + '\\n'; 1090 | QString escaped_libs = qc_prepare_libs(normalizedLibs); 1091 | if (!escaped_libs.isEmpty()) 1092 | pro += "LIBS += " + escaped_libs + '\\n'; 1093 | pro += proextra; 1094 | 1095 | fname = dir.filePath("atest.pro"); 1096 | f.setFileName(fname); 1097 | if (!f.open(QFile::WriteOnly | QFile::Truncate)) { 1098 | debug("unable to open atest.pro for writing"); 1099 | return false; 1100 | } 1101 | if (f.write(pro.toLatin1()) == -1) { 1102 | debug("error writing to atest.pro"); 1103 | return false; 1104 | } 1105 | f.close(); 1106 | 1107 | debug(QString("Wrote atest.pro:\\n%1").arg(pro)); 1108 | 1109 | QString oldpath = QDir::currentPath(); 1110 | QDir::setCurrent(dir.path()); 1111 | 1112 | bool ok = false; 1113 | int r = doCommand(qmake_path, QStringList() << "atest.pro"); 1114 | if (r == 0) { 1115 | r = doCommand(maketool, QStringList()); 1116 | if (r == 0) { 1117 | ok = true; 1118 | if (retcode) { 1119 | QString runatest = out; 1120 | #ifdef Q_OS_UNIX 1121 | runatest.prepend("./"); 1122 | #endif 1123 | *retcode = doCommand(runatest, QStringList()); 1124 | } 1125 | } 1126 | r = doCommand(maketool, QStringList() << "distclean"); 1127 | if (r != 0) 1128 | debug("error during atest distclean"); 1129 | } 1130 | 1131 | QDir::setCurrent(oldpath); 1132 | 1133 | // cleanup 1134 | // dir.remove("atest.pro"); 1135 | // dir.remove("atest.cpp"); 1136 | // tmp.rmdir("atest"); 1137 | 1138 | // remove whole dir since distclean doesn't always work 1139 | qc_removedir(tmp.filePath("atest")); 1140 | 1141 | if (!ok) 1142 | return false; 1143 | return true; 1144 | } 1145 | 1146 | bool Conf::checkHeader(const QString &path, const QString &h) { return QDir(path).exists(h); } 1147 | 1148 | bool Conf::findHeader(const QString &h, const QStringList &ext, QString *inc) 1149 | { 1150 | if (checkHeader("/usr/include", h)) { 1151 | *inc = ""; 1152 | return true; 1153 | } 1154 | QStringList dirs; 1155 | dirs += "/usr/local/include"; 1156 | dirs += ext; 1157 | 1158 | QString prefix = qc_getenv("PREFIX"); 1159 | if (!prefix.isEmpty()) { 1160 | prefix += "/include"; 1161 | prefix = qc_normalize_path(prefix); 1162 | if (!dirs.contains(prefix)) 1163 | dirs << prefix; 1164 | } 1165 | 1166 | for (QStringList::ConstIterator it = dirs.begin(); it != dirs.end(); ++it) { 1167 | if (checkHeader(*it, h)) { 1168 | *inc = *it; 1169 | return true; 1170 | } 1171 | } 1172 | return false; 1173 | } 1174 | 1175 | bool Conf::checkLibrary(const QString &path, const QString &name) 1176 | { 1177 | QString str = 1178 | //"#include \\n" 1179 | "int main()\\n" 1180 | "{\\n" 1181 | //" printf(\\"library checker running\\\\\\\\n\\");\\n" 1182 | " return 0;\\n" 1183 | "}\\n"; 1184 | 1185 | QString libs; 1186 | if (!path.isEmpty()) 1187 | libs += QString("-L") + path + ' '; 1188 | libs += QString("-l") + name; 1189 | if (!doCompileAndLink(str, QStringList(), libs, QString())) 1190 | return false; 1191 | return true; 1192 | } 1193 | 1194 | bool Conf::findLibrary(const QString &name, QString *lib) 1195 | { 1196 | if (checkLibrary("", name)) { 1197 | *lib = ""; 1198 | return true; 1199 | } 1200 | if (checkLibrary("/usr/local/lib", name)) { 1201 | *lib = "/usr/local/lib"; 1202 | return true; 1203 | } 1204 | 1205 | QString prefix = qc_getenv("PREFIX"); 1206 | if (!prefix.isEmpty()) { 1207 | prefix += "/lib"; 1208 | prefix = qc_normalize_path(prefix); 1209 | if (checkLibrary(prefix, name)) { 1210 | *lib = prefix; 1211 | return true; 1212 | } 1213 | } 1214 | 1215 | return false; 1216 | } 1217 | 1218 | QString Conf::findProgram(const QString &prog) { return qc_findprogram(prog); } 1219 | 1220 | bool Conf::findSimpleLibrary(const QString &incvar, const QString &libvar, const QString &incname, 1221 | const QString &libname, QString *incpath, QString *libs) 1222 | { 1223 | QString inc, lib; 1224 | QString s; 1225 | 1226 | s = getenv(incvar).trimmed(); 1227 | if (!s.isEmpty()) { 1228 | if (!checkHeader(s, incname)) { 1229 | if (debug_enabled) 1230 | printf("%s is not found in \\"%s\\"\\n", qPrintable(incname), qPrintable(s)); 1231 | return false; 1232 | } 1233 | inc = s; 1234 | } else { 1235 | if (!findHeader(incname, QStringList(), &s)) { 1236 | if (debug_enabled) 1237 | printf("%s is not found anywhere\\n", qPrintable(incname)); 1238 | return false; 1239 | } 1240 | inc = s; 1241 | } 1242 | 1243 | s = getenv(libvar).trimmed(); 1244 | if (!s.isEmpty()) { 1245 | if (!checkLibrary(s, libname)) { 1246 | if (debug_enabled) 1247 | printf("%s is not found in \\"%s\\"\\n", qPrintable(libname), qPrintable(s)); 1248 | return false; 1249 | } 1250 | lib = s; 1251 | } else { 1252 | if (!findLibrary(libname, &s)) { 1253 | if (debug_enabled) 1254 | printf("%s is not found anywhere\\n", qPrintable(libname)); 1255 | return false; 1256 | } 1257 | lib = s; 1258 | } 1259 | 1260 | QString lib_out; 1261 | if (!lib.isEmpty()) 1262 | lib_out += QString("-L") + s + " "; 1263 | lib_out += QString("-l") + libname; 1264 | 1265 | *incpath = inc; 1266 | *libs = lib_out; 1267 | return true; 1268 | } 1269 | 1270 | bool Conf::findFooConfig(const QString &path, QString *version, QStringList *incs, QString *libs, QString *otherflags) 1271 | { 1272 | QStringList args; 1273 | QByteArray out; 1274 | int ret; 1275 | 1276 | args += "--version"; 1277 | ret = doCommand(path, args, &out); 1278 | if (ret != 0) 1279 | return false; 1280 | 1281 | QString version_out = QString::fromLatin1(out).trimmed(); 1282 | 1283 | args.clear(); 1284 | args += "--libs"; 1285 | ret = doCommand(path, args, &out); 1286 | if (ret != 0) 1287 | return false; 1288 | 1289 | QString libs_out = QString::fromLatin1(out).trimmed(); 1290 | 1291 | args.clear(); 1292 | args += "--cflags"; 1293 | ret = doCommand(path, args, &out); 1294 | if (ret != 0) 1295 | return false; 1296 | 1297 | QString cflags = QString::fromLatin1(out).trimmed(); 1298 | 1299 | QStringList incs_out, otherflags_out; 1300 | qc_splitcflags(cflags, &incs_out, &otherflags_out); 1301 | 1302 | *version = version_out; 1303 | *incs = incs_out; 1304 | *libs = libs_out; 1305 | *otherflags = otherflags_out.join(QLatin1String(" ")); 1306 | return true; 1307 | } 1308 | 1309 | bool Conf::findPkgConfig(const QString &name, VersionMode mode, const QString &req_version, QString *version, 1310 | QStringList *incs, QString *libs, QString *otherflags) 1311 | { 1312 | QStringList args; 1313 | QByteArray out; 1314 | int ret; 1315 | 1316 | args += name; 1317 | args += "--exists"; 1318 | ret = doCommand("pkg-config", args, &out); 1319 | if (ret != 0) 1320 | return false; 1321 | 1322 | if (mode != VersionAny) { 1323 | args.clear(); 1324 | args += name; 1325 | if (mode == VersionMin) 1326 | args += QString("--atleast-version=%1").arg(req_version); 1327 | else if (mode == VersionMax) 1328 | args += QString("--max-version=%1").arg(req_version); 1329 | else 1330 | args += QString("--exact-version=%1").arg(req_version); 1331 | ret = doCommand("pkg-config", args, &out); 1332 | if (ret != 0) 1333 | return false; 1334 | } 1335 | 1336 | args.clear(); 1337 | args += name; 1338 | args += "--modversion"; 1339 | ret = doCommand("pkg-config", args, &out); 1340 | if (ret != 0) 1341 | return false; 1342 | 1343 | QString version_out = QString::fromLatin1(out).trimmed(); 1344 | 1345 | args.clear(); 1346 | args += name; 1347 | args += "--libs"; 1348 | ret = doCommand("pkg-config", args, &out); 1349 | if (ret != 0) 1350 | return false; 1351 | 1352 | QString libs_out = QString::fromLatin1(out).trimmed(); 1353 | 1354 | args.clear(); 1355 | args += name; 1356 | args += "--cflags"; 1357 | ret = doCommand("pkg-config", args, &out); 1358 | if (ret != 0) 1359 | return false; 1360 | 1361 | QString cflags = QString::fromLatin1(out).trimmed(); 1362 | 1363 | QStringList incs_out, otherflags_out; 1364 | qc_splitcflags(cflags, &incs_out, &otherflags_out); 1365 | 1366 | *version = version_out; 1367 | *incs = incs_out; 1368 | *libs = libs_out; 1369 | *otherflags = otherflags_out.join(QLatin1String(" ")); 1370 | return true; 1371 | } 1372 | 1373 | void Conf::addDefine(const QString &str) 1374 | { 1375 | if (DEFINES.isEmpty()) 1376 | DEFINES = str; 1377 | else 1378 | DEFINES += QString(" ") + str; 1379 | debug(QString("DEFINES += %1").arg(str)); 1380 | } 1381 | 1382 | void Conf::addLib(const QString &str) 1383 | { 1384 | QStringList libs = qc_splitflags(str); 1385 | foreach (const QString &lib, libs) { 1386 | if (lib.startsWith("-l")) { 1387 | LIBS.append(lib); 1388 | } else { 1389 | LIBS.append(qc_normalize_path(lib)); // we don't care about -L prefix since normalier does not touch it. 1390 | } 1391 | } 1392 | debug(QString("LIBS += %1").arg(str)); 1393 | } 1394 | 1395 | void Conf::addIncludePath(const QString &str) 1396 | { 1397 | INCLUDEPATH.append(qc_normalize_path(str)); 1398 | debug(QString("INCLUDEPATH += %1").arg(str)); 1399 | } 1400 | 1401 | void Conf::addExtra(const QString &str) 1402 | { 1403 | extra += str + '\\n'; 1404 | debug(QString("extra += %1").arg(str)); 1405 | } 1406 | 1407 | //---------------------------------------------------------------------------- 1408 | // main 1409 | //---------------------------------------------------------------------------- 1410 | #include "conf4.moc" 1411 | 1412 | #ifdef HAVE_MODULES 1413 | #include "modules.cpp" 1414 | #endif 1415 | 1416 | int main(int argc, char **argv) 1417 | { 1418 | QCoreApplication app(argc, argv); 1419 | Conf * conf = new Conf; 1420 | ConfObj * o = 0; 1421 | Q_UNUSED(o); 1422 | #ifdef HAVE_MODULES 1423 | #include "modules_new.cpp" 1424 | #endif 1425 | 1426 | conf->debug_enabled = (qc_getenv("QC_VERBOSE") == "Y") ? true : false; 1427 | if (conf->debug_enabled) 1428 | printf(" -> ok\\n"); 1429 | else 1430 | printf("ok\\n"); 1431 | 1432 | QString confCommand = qc_getenv("QC_COMMAND"); 1433 | QString proName = qc_getenv("QC_PROFILE"); 1434 | conf->qmake_path = qc_getenv("QC_QMAKE"); 1435 | conf->qmakespec = qc_getenv("QC_QMAKESPEC"); 1436 | conf->maketool = qc_getenv("QC_MAKETOOL"); 1437 | 1438 | if (conf->debug_enabled) 1439 | printf("conf command: [%s]\\n", qPrintable(confCommand)); 1440 | 1441 | QString confPath = qc_findself(confCommand); 1442 | if (confPath.isEmpty()) { 1443 | printf("Error: cannot find myself; rerun with an absolute path\\n"); 1444 | return 1; 1445 | } 1446 | 1447 | QString srcdir = QFileInfo(confPath).absolutePath(); 1448 | QString builddir = QDir::current().absolutePath(); 1449 | QString proPath = QDir(srcdir).filePath(proName); 1450 | 1451 | if (conf->debug_enabled) { 1452 | printf("conf path: [%s]\\n", qPrintable(confPath)); 1453 | printf("srcdir: [%s]\\n", qPrintable(srcdir)); 1454 | printf("builddir: [%s]\\n", qPrintable(builddir)); 1455 | printf("profile: [%s]\\n", qPrintable(proPath)); 1456 | printf("qmake path: [%s]\\n", qPrintable(conf->qmake_path)); 1457 | printf("qmakespec: [%s]\\n", qPrintable(conf->qmakespec)); 1458 | printf("make tool: [%s]\\n", qPrintable(conf->maketool)); 1459 | printf("\\n"); 1460 | } 1461 | 1462 | bool success = false; 1463 | if (conf->exec()) { 1464 | QFile f("conf.pri"); 1465 | if (!f.open(QFile::WriteOnly | QFile::Truncate)) { 1466 | printf("Error writing %s\\n", qPrintable(f.fileName())); 1467 | return 1; 1468 | } 1469 | 1470 | QString str; 1471 | str += "# qconf\\n\\n"; 1472 | str += "greaterThan(QT_MAJOR_VERSION, 4):CONFIG += c++11\\n"; 1473 | 1474 | QString var; 1475 | var = qc_normalize_path(qc_getenv("PREFIX")); 1476 | if (!var.isEmpty()) 1477 | str += QString("PREFIX = %1\\n").arg(var); 1478 | var = qc_normalize_path(qc_getenv("BINDIR")); 1479 | if (!var.isEmpty()) 1480 | str += QString("BINDIR = %1\\n").arg(var); 1481 | var = qc_normalize_path(qc_getenv("INCDIR")); 1482 | if (!var.isEmpty()) 1483 | str += QString("INCDIR = %1\\n").arg(var); 1484 | var = qc_normalize_path(qc_getenv("LIBDIR")); 1485 | if (!var.isEmpty()) 1486 | str += QString("LIBDIR = %1\\n").arg(var); 1487 | var = qc_normalize_path(qc_getenv("DATADIR")); 1488 | if (!var.isEmpty()) 1489 | str += QString("DATADIR = %1\\n").arg(var); 1490 | str += '\\n'; 1491 | 1492 | if (qc_getenv("QC_STATIC") == "Y") 1493 | str += "CONFIG += staticlib\\n"; 1494 | 1495 | // TODO: don't need this? 1496 | // str += "QT_PATH_PLUGINS = " + QString(qInstallPathPlugins()) + '\\n'; 1497 | 1498 | if (!conf->DEFINES.isEmpty()) 1499 | str += "DEFINES += " + conf->DEFINES + '\\n'; 1500 | if (!conf->INCLUDEPATH.isEmpty()) 1501 | str += "INCLUDEPATH += " + qc_prepare_includepath(conf->INCLUDEPATH) + '\\n'; 1502 | if (!conf->LIBS.isEmpty()) 1503 | str += "LIBS += " + qc_prepare_libs(conf->LIBS) + '\\n'; 1504 | if (!conf->extra.isEmpty()) 1505 | str += conf->extra; 1506 | str += '\\n'; 1507 | 1508 | var = qc_getenv("QC_EXTRACONF"); 1509 | if (!var.isEmpty()) 1510 | str += ("\\n# Extra conf from command line\\n" + var + "\\n"); 1511 | 1512 | QByteArray cs = str.toLatin1(); 1513 | f.write(cs); 1514 | f.close(); 1515 | success = true; 1516 | } 1517 | QString qmake_path = conf->qmake_path; 1518 | QString qmakespec = conf->qmakespec; 1519 | delete conf; 1520 | 1521 | if (!success) 1522 | return 1; 1523 | 1524 | // run qmake on the project file 1525 | QStringList args; 1526 | if (!qmakespec.isEmpty()) { 1527 | args += "-spec"; 1528 | args += qmakespec; 1529 | } 1530 | args += proPath; 1531 | int ret = qc_runprogram(qmake_path, args, 0, true); 1532 | if (ret != 0) 1533 | return 1; 1534 | 1535 | return 0; 1536 | } 1537 | 1538 | EOT 1539 | cat >"$1/conf4.pro" </dev/null 1571 | else 1572 | "$qm" conf4.pro >/dev/null 1573 | fi 1574 | $MAKE clean >/dev/null 2>&1 1575 | $MAKE >../conf.log 2>&1 1576 | ) 1577 | 1578 | if [ "$?" != "0" ]; then 1579 | rm -rf ".qconftemp" 1580 | if [ "$QC_VERBOSE" = "Y" ]; then 1581 | echo " -> fail" 1582 | else 1583 | echo "fail" 1584 | fi 1585 | printf "\n" 1586 | printf "Reason: There was an error compiling 'conf'. See conf.log for details.\n" 1587 | printf "\n" 1588 | show_qt_info 1589 | if [ "$QC_VERBOSE" = "Y" ]; then 1590 | echo "conf.log:" 1591 | cat conf.log 1592 | fi 1593 | exit 1; 1594 | fi 1595 | 1596 | QC_COMMAND=$0 1597 | export QC_COMMAND 1598 | QC_PROFILE=qconf.pro 1599 | export QC_PROFILE 1600 | QC_QMAKE="$qm" 1601 | export QC_QMAKE 1602 | QC_QMAKESPEC=$qm_spec 1603 | export QC_QMAKESPEC 1604 | QC_MAKETOOL=$MAKE 1605 | export QC_MAKETOOL 1606 | ".qconftemp/conf" 1607 | ret="$?" 1608 | if [ "$ret" = "1" ]; then 1609 | rm -rf ".qconftemp" 1610 | echo 1611 | exit 1; 1612 | else 1613 | if [ "$ret" != "0" ]; then 1614 | rm -rf ".qconftemp" 1615 | if [ "$QC_VERBOSE" = "Y" ]; then 1616 | echo " -> fail" 1617 | else 1618 | echo "fail" 1619 | fi 1620 | echo 1621 | echo "Reason: Unexpected error launching 'conf'" 1622 | echo 1623 | exit 1; 1624 | fi 1625 | fi 1626 | rm -rf ".qconftemp" 1627 | 1628 | echo 1629 | echo "Good, your configure finished. Now run $MAKE." 1630 | echo 1631 | -------------------------------------------------------------------------------- /src/qconf.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * qconf.cpp - main qconf source 3 | * Copyright (C) 2003-2009 Justin Karneges 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU General Public License 7 | * as published by the Free Software Foundation; either version 2 8 | * of the License, or (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this library; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 18 | */ 19 | 20 | #include 21 | #include 22 | 23 | // for chmod 24 | #include 25 | #include 26 | 27 | #include "stringhelp.h" 28 | 29 | #define VERSION "2.0" 30 | 31 | #define CONF_USAGE_SPACE 4 32 | #define CONF_WRAP 78 33 | 34 | bool looksLikeInPlace(const QString &path) 35 | { 36 | QFileInfo confinfo(path + "/conf"); 37 | QFileInfo modulesinfo(path + "/modules"); 38 | if (confinfo.exists() && confinfo.isDir() && modulesinfo.exists() && modulesinfo.isDir()) 39 | return true; 40 | return false; 41 | } 42 | 43 | QString escapeFile(const QString &str) 44 | { 45 | QString out; 46 | for (int n = 0; n < (int)str.length(); ++n) { 47 | if (str[n] == '$' || str[n] == '`' || str[n] == '\\') 48 | out += '\\'; 49 | out += str[n]; 50 | } 51 | return out; 52 | } 53 | 54 | QString escapeArg(const QString &str) 55 | { 56 | QString out; 57 | for (int n = 0; n < (int)str.length(); ++n) { 58 | if (str[n] == '-') 59 | out += '_'; 60 | else 61 | out += str[n]; 62 | } 63 | return out; 64 | } 65 | 66 | QString c_escape(const QString &in) 67 | { 68 | QString out; 69 | for (int n = 0; n < in.length(); ++n) { 70 | /*if(in[n] == '\\') 71 | out += "\\\\"; 72 | else*/ 73 | if (in[n] == '\"') 74 | out += "\\\""; 75 | else if (in[n] == '\n') 76 | out += "\\n"; 77 | else 78 | out += in[n]; 79 | } 80 | return out; 81 | } 82 | 83 | QString echoBlock(int tabs, const QString &in) 84 | { 85 | QStringList pars = in.split('\n', Qt::KeepEmptyParts); 86 | if (!pars.isEmpty() && pars.last().isEmpty()) 87 | pars.removeLast(); 88 | QStringList lines; 89 | int n; 90 | for (n = 0; n < pars.count(); ++n) { 91 | QStringList list = wrapString(pars[n], CONF_WRAP); 92 | for (int n2 = 0; n2 < list.count(); ++n2) 93 | lines.append(list[n2]); 94 | } 95 | 96 | QString str; 97 | for (n = 0; n < lines.count(); ++n) { 98 | QString out; 99 | out.fill((char)9, tabs); // 9 == tab character 100 | if (lines[n].isEmpty()) 101 | out += QString("printf \"\\n\"\n"); 102 | else 103 | out += QString("printf \"%1\\n\"\n").arg(c_escape(lines[n])); 104 | str += out; 105 | } 106 | return str; 107 | } 108 | 109 | QString formatBlock(const QString &in) 110 | { 111 | QStringList pars = in.split('\n', Qt::KeepEmptyParts); 112 | if (!pars.isEmpty() && pars.last().isEmpty()) 113 | pars.removeLast(); 114 | QStringList lines; 115 | int n; 116 | for (n = 0; n < pars.count(); ++n) { 117 | QStringList list = wrapString(pars[n], CONF_WRAP); 118 | for (int n2 = 0; n2 < list.count(); ++n2) 119 | lines.append(list[n2]); 120 | } 121 | 122 | QString str; 123 | for (n = 0; n < lines.count(); ++n) 124 | str += lines[n] + '\n'; 125 | return str; 126 | } 127 | 128 | static void write32(quint8 *out, quint32 i) 129 | { 130 | out[0] = (i >> 24) & 0xff; 131 | out[1] = (i >> 16) & 0xff; 132 | out[2] = (i >> 8) & 0xff; 133 | out[3] = i & 0xff; 134 | } 135 | 136 | static QByteArray lenval(const QByteArray &in) 137 | { 138 | QByteArray out; 139 | out.resize(4); 140 | write32((quint8 *)out.data(), in.size()); 141 | out += in; 142 | return out; 143 | } 144 | 145 | static QByteArray embed_file(const QString &name, const QByteArray &data) 146 | { 147 | QByteArray out; 148 | out += lenval(name.toLatin1()); 149 | out += lenval(data); 150 | return out; 151 | } 152 | 153 | static QByteArray get_configexe_stub() 154 | { 155 | QFile f; 156 | f.setFileName(":/configexe/configexe_stub.exe"); 157 | if (!f.open(QIODevice::ReadOnly)) { 158 | // for debugging purposes, if .exe stub isn't found, use 159 | // possible unix stub 160 | f.setFileName(":/configexe/configexe_stub"); 161 | if (!f.open(QIODevice::ReadOnly)) 162 | return QByteArray(); 163 | } 164 | return f.readAll(); 165 | } 166 | 167 | const char *qt4_info_str 168 | = "Be sure you have a proper Qt 4.0+ build environment set up. This means not just Qt, " 169 | "but also a C++ compiler, a make tool, and any other packages necessary " 170 | "for compiling C++ programs.\n" 171 | "\n" 172 | "If you are certain everything is installed, then it could be that Qt is not being " 173 | "recognized or that a different version of Qt is being detected by mistake (for example, " 174 | "this could happen if \\$QTDIR is pointing to a Qt 3 installation). At least one of " 175 | "the following conditions must be satisfied:\n" 176 | "\n" 177 | " 1) --qtdir is set to the location of Qt\n" 178 | " 2) \\$QTDIR is set to the location of Qt\n" 179 | " 3) QtCore is in the pkg-config database\n" 180 | " 4) qmake is in the \\$PATH\n" 181 | "\n" 182 | "This script will use the first one it finds to be true, checked in the above order. #3 and #4 are the " 183 | "recommended options. #1 and #2 are mainly for overriding the system configuration.\n" 184 | "\n"; 185 | 186 | const char *qt4_info_str_win 187 | = "Be sure you have a proper Qt 4.0+ build environment set up. This means not just Qt, " 188 | "but also a C++ compiler, a make tool, and any other packages necessary " 189 | "for compiling C++ programs.\n" 190 | "\n" 191 | "If you are certain everything is installed, then it could be that Qt is not being " 192 | "recognized or that a different version of Qt is being detected by mistake (for example, " 193 | "this could happen if %QTDIR% is pointing to a Qt 3 installation). At least one of " 194 | "the following conditions must be satisfied:\n" 195 | "\n" 196 | " 1) --qtdir is set to the location of Qt\n" 197 | " 2) %QTDIR% is set to the location of Qt\n" 198 | " 3) qmake is in the %PATH%\n" 199 | "\n" 200 | "This program will use the first one it finds to be true, checked in the above order.\n" 201 | "\n"; 202 | 203 | class ConfUsageOpt { 204 | public: 205 | ConfUsageOpt(const QString &_name = "", const QString &_arg = "", const QString &_desc = "") : 206 | name(_name), arg(_arg), desc(_desc) 207 | { 208 | } 209 | 210 | QString generateFirst() const 211 | { 212 | QString line = QString(" --%1").arg(name); 213 | if (!arg.isEmpty()) 214 | line += QString("=[%1]").arg(arg); 215 | return line; 216 | } 217 | 218 | QString generate(int indent, int width) const 219 | { 220 | QString str; 221 | QStringList descLines = wrapString(desc, width); 222 | bool first = true; 223 | // printf("lines:%d,indent:%d\n", descLines.count(), indent); 224 | for (QStringList::ConstIterator it = descLines.begin(); it != descLines.end(); ++it) { 225 | QString line; 226 | if (first) { 227 | line = generateFirst(); 228 | first = false; 229 | } 230 | while ((int)line.length() < indent) 231 | line += ' '; 232 | line += *it; 233 | str += line + '\n'; 234 | } 235 | return str; 236 | } 237 | 238 | QString name, arg, desc; 239 | }; 240 | 241 | class ConfOpt { 242 | public: 243 | ConfOpt(const QString &_name = "", const QString &_arg = "", const QString &_var = "", const QString &_desc = "") : 244 | name(_name), arg(_arg), var(_var), desc(_desc) 245 | { 246 | } 247 | 248 | QString name, arg, var, desc; 249 | bool hidden = false; // invisible in usage 250 | }; 251 | 252 | class ConfGen { 253 | public: 254 | QList mainopts; 255 | QList appopts; 256 | QList depopts; 257 | QList all; 258 | QString name; 259 | QString profile; 260 | QByteArray filemodulescpp, filemodulesnewcpp, fileconfh, fileconfcpp, fileconfpro; 261 | bool libmode, usePrefix, useBindir, useIncdir, useLibdir, useDatadir; 262 | bool qt4, byoq; 263 | 264 | ConfGen() 265 | { 266 | libmode = false; 267 | usePrefix = true; 268 | useBindir = true; 269 | useIncdir = false; 270 | useLibdir = false; 271 | useDatadir = false; 272 | qt4 = false; 273 | byoq = false; 274 | 275 | // extra 276 | // extraopts += ConfOpt("zlib-inc", "path", "QC_ZLIB_INC", "Specify path to zlib include files."); 277 | // extraopts += ConfOpt("zlib-lib", "path", "QC_ZLIB_LIB", "Specify path to zlib library files."); 278 | // extraopts += ConfOpt("disable-dnotify", "", "QC_DISABLE_DNOTIFY", "Disable Linux DNOTIFY."); 279 | } 280 | 281 | ConfOpt &addDepOption(const QString &name, const QString &arg, const QString &var, const QString &desc) 282 | { 283 | ConfOpt opt; 284 | opt.name = name; 285 | opt.arg = arg; 286 | opt.var = var; 287 | opt.desc = desc; 288 | opt.hidden = desc.isEmpty(); 289 | depopts += opt; 290 | return depopts.last(); 291 | } 292 | 293 | ConfOpt &addAppOption(const QString &name, const QString &arg, const QString &var, const QString &desc) 294 | { 295 | ConfOpt opt; 296 | opt.name = name; 297 | opt.arg = arg; 298 | opt.var = var; 299 | opt.desc = desc; 300 | opt.hidden = desc.isEmpty(); 301 | appopts += opt; 302 | return appopts.last(); 303 | } 304 | 305 | ConfOpt &addOption(const QString §ion, const QString &name, const QString &arg, const QString &var, 306 | const QString &desc = QString()) 307 | { 308 | if (section == "project") 309 | return addAppOption(name, arg, var, desc); 310 | return addDepOption(name, arg, var, desc); 311 | } 312 | 313 | QByteArray generate() 314 | { 315 | // main options 316 | mainopts.clear(); 317 | if (usePrefix) { 318 | mainopts += ConfOpt("prefix", "path", "PREFIX", "Base path for build/install. Default: /usr/local"); 319 | if (useBindir) 320 | mainopts += ConfOpt("bindir", "path", "BINDIR", "Directory for binaries. Default: PREFIX/bin"); 321 | if (useIncdir) 322 | mainopts += ConfOpt("includedir", "path", "INCDIR", "Directory for headers. Default: PREFIX/include"); 323 | if (useLibdir) 324 | mainopts += ConfOpt("libdir", "path", "LIBDIR", "Directory for libraries. Default: PREFIX/lib"); 325 | if (useDatadir) 326 | mainopts += ConfOpt("datadir", "path", "DATADIR", "Directory for data. Default: PREFIX/share"); 327 | } 328 | if (!byoq) 329 | mainopts += ConfOpt("qtdir", "path", "EX_QTDIR", "Directory where Qt is installed."); 330 | 331 | if (libmode) 332 | mainopts += ConfOpt("static", QString(), "QC_STATIC", "Create a static library instead of shared."); 333 | 334 | mainopts += ConfOpt("extraconf", "conf", "QC_EXTRACONF", "Extra configuration for nonstandard cases."); 335 | 336 | QString str; 337 | str += genHeader(); 338 | str += genUsage(); 339 | str += genFindStuff(); 340 | str += genQtInfo(); 341 | 342 | // combine main and extra opts together 343 | all = mainopts + appopts + depopts; 344 | 345 | /*str += 346 | "# save environment variable\n" 347 | "ORIG_QTDIR=$QTDIR\n\n";*/ 348 | 349 | // argument parsing 350 | str += createConfArgsSection(); 351 | 352 | // set the builtin defaults 353 | if (usePrefix) { 354 | str += "PREFIX=${PREFIX:-/usr/local}\n"; 355 | if (useBindir) 356 | str += "BINDIR=${BINDIR:-$PREFIX/bin}\n"; 357 | if (useIncdir) 358 | str += "INCDIR=${INCDIR:-$PREFIX/include}\n"; 359 | if (useLibdir) 360 | str += "LIBDIR=${LIBDIR:-$PREFIX/lib}\n"; 361 | if (useDatadir) 362 | str += "DATADIR=${DATADIR:-$PREFIX/share}\n"; 363 | } 364 | str += '\n'; 365 | 366 | str += QString("echo \"Configuring %1 ...\"\n\n").arg(name); 367 | 368 | // display values 369 | str += "if [ \"$QC_VERBOSE\" = \"Y\" ]; then\n"; 370 | str += "echo\n"; 371 | for (QList::ConstIterator it = all.begin(); it != all.end(); ++it) { 372 | const ConfOpt &i = *it; 373 | str += QString("echo %1=$%2\n").arg(i.var).arg(i.var); 374 | } 375 | str += "echo\n"; 376 | str += "fi\n\n"; 377 | 378 | if (qt4) { 379 | if (byoq) { 380 | str += "printf \"Preparing internal Qt 4+ build environment ... \"\n\n"; 381 | 382 | str += "cd byoq\n"; 383 | str += "./byoq build\n"; 384 | str += "ret=\"$?\"\n"; 385 | str += "cd ..\n"; 386 | str += "if [ \"$ret\" != \"0\" ]; then\n"; 387 | str += " exit 1\n"; 388 | str += "fi\n"; 389 | str += "unset QTDIR\n"; 390 | str += "unset QMAKESPEC\n"; 391 | // NOTE: if this is ever uncommented, remember 392 | // that exporting with a set is a bashism 393 | // str += "if [ \"$QMAKESPEC\" == \"\" ]; then\n"; 394 | // str += " export QMAKESPEC=linux-g++\n"; 395 | // str += "fi\n"; 396 | str += "qm=$PWD/byoq/qt/bin/qmake\n\n"; 397 | } 398 | 399 | str += "printf \"Verifying Qt build environment ... \"\n\n"; 400 | if (!byoq) 401 | str += genQt4Checks(); 402 | } 403 | 404 | str += genEmbeddedFiles(); 405 | 406 | // export all values 407 | for (QList::ConstIterator it = all.begin(); it != all.end(); ++it) { 408 | const ConfOpt &i = *it; 409 | str += QString("export %1\n").arg(i.var); 410 | } 411 | str += "export QC_VERBOSE\n"; // export verbose flag also 412 | str += "export QC_QTSELECT\n"; 413 | 414 | str += genDoQConf(); 415 | 416 | // newer versions have this stuff in the conf program 417 | if (!qt4) { 418 | str += genRunExtra(); 419 | str += genRunQMake(); 420 | } 421 | 422 | str += genFooter(); 423 | 424 | return str.toLatin1(); 425 | } 426 | 427 | QByteArray generateExe() 428 | { 429 | // main options 430 | mainopts.clear(); 431 | mainopts += ConfOpt("qtdir", "path", "EX_QTDIR", "Directory where Qt is installed."); 432 | 433 | if (usePrefix) { 434 | mainopts += ConfOpt("prefix", "path", "PREFIX", "Base path for build/install. No default."); 435 | if (useBindir) 436 | mainopts += ConfOpt("bindir", "path", "BINDIR", "Directory for binaries. Default: PREFIX/bin"); 437 | if (useIncdir) 438 | mainopts += ConfOpt("includedir", "path", "INCDIR", "Directory for headers. Default: PREFIX/include"); 439 | if (useLibdir) 440 | mainopts += ConfOpt("libdir", "path", "LIBDIR", "Directory for libraries. Default: PREFIX/lib"); 441 | if (useDatadir) 442 | mainopts += ConfOpt("datadir", "path", "DATADIR", "Directory for data. Default: PREFIX/share"); 443 | } 444 | 445 | if (libmode) 446 | mainopts += ConfOpt("static", QString(), "QC_STATIC", "Create a static library instead of shared."); 447 | 448 | mainopts += ConfOpt("extraconf", "conf", "QC_EXTRACONF", "Extra configuration for nonstandard cases"); 449 | 450 | // combine main and extra opts together 451 | all = mainopts + appopts + depopts; 452 | 453 | QByteArray out = get_configexe_stub(); 454 | QByteArray sig = "QCONF_CONFIGWIN_BLOCKSIG_68b7e7d7"; 455 | QByteArray datasec = makeDatasec(); 456 | out += sig; 457 | out += lenval(datasec); 458 | return out; 459 | } 460 | 461 | QByteArray makeDatasec() const 462 | { 463 | QByteArray out; 464 | QByteArray buf(4, 0); 465 | 466 | out += lenval(genUsageOutput().toLatin1()); 467 | 468 | write32((quint8 *)buf.data(), all.count()); 469 | out += buf; 470 | for (int n = 0; n < all.count(); ++n) { 471 | const ConfOpt &i = all[n]; 472 | out += lenval(i.name.toLatin1()); 473 | out += lenval(i.var.toLatin1()); 474 | if (!i.arg.isEmpty()) 475 | out += (char)0; 476 | else 477 | out += (char)1; 478 | } 479 | 480 | write32((quint8 *)buf.data(), 5); 481 | out += buf; 482 | out += embed_file("modules.cpp", filemodulescpp); 483 | out += embed_file("modules_new.cpp", filemodulesnewcpp); 484 | out += embed_file("conf4.h", fileconfh); 485 | out += embed_file("conf4.cpp", fileconfcpp); 486 | out += embed_file("conf4.pro", fileconfpro); 487 | 488 | out += lenval(name.toLatin1()); 489 | out += lenval(profile.toLatin1()); 490 | 491 | out += lenval(formatBlock(qt4_info_str_win).toLatin1()); 492 | 493 | return out; 494 | } 495 | 496 | private: 497 | QString genHeader() 498 | { 499 | QString str = QString("#!/bin/sh\n" 500 | "#\n" 501 | "# Generated by qconf %1 ( https://github.com/psi-plus/qconf )\n" 502 | "#\n" 503 | "\n") 504 | .arg(VERSION); 505 | return str; 506 | } 507 | 508 | QString genFooter() 509 | { 510 | QString str = "echo\n"; 511 | //"if [ \"$QTDIR\" != \"$ORIG_QTDIR\" ]; then\n" 512 | //" echo Good, your configure finished. Now run \\'QTDIR=$QTDIR make\\'.\n" 513 | //"else\n" 514 | if (qt4) 515 | str += "echo \"Good, your configure finished. Now run $MAKE.\"\n"; 516 | //"fi\n" 517 | str += "echo\n"; 518 | return str; 519 | } 520 | 521 | int getUsageIndent(const QList &list) const 522 | { 523 | int largest = 0; 524 | for (QList::ConstIterator it = list.begin(); it != list.end(); ++it) { 525 | const ConfUsageOpt &opt = *it; 526 | QString tmp = opt.generateFirst(); 527 | if ((int)tmp.length() > largest) 528 | largest = tmp.length(); 529 | } 530 | return largest; 531 | } 532 | 533 | QList optsToUsage(const QList &list) const 534 | { 535 | QList out; 536 | for (auto const &opt : list) { 537 | if (!opt.hidden) 538 | out += ConfUsageOpt(opt.name, opt.arg, opt.desc); 539 | } 540 | return out; 541 | } 542 | 543 | QString genUsageSection(const QString &title, const QList &list) const 544 | { 545 | QString str; 546 | str += title; 547 | str += '\n'; 548 | int indent = getUsageIndent(list) + CONF_USAGE_SPACE; 549 | for (QList::ConstIterator it = list.begin(); it != list.end(); ++it) { 550 | const ConfUsageOpt &opt = *it; 551 | str += opt.generate(indent, CONF_WRAP - indent); 552 | } 553 | str += "\n"; 554 | return str; 555 | } 556 | 557 | QString genUsage() 558 | { 559 | QString str = "show_usage() {\ncat < list = optsToUsage(mainopts); 564 | list += ConfUsageOpt("verbose", "", "Show extra configure output."); 565 | list += ConfUsageOpt("qtselect", "N", "Select major Qt version (4 or 5)."); 566 | list += ConfUsageOpt("help", "", "This help text."); 567 | str += genUsageSection("Main options:", list); 568 | 569 | if (!appopts.isEmpty()) { 570 | list = optsToUsage(appopts); 571 | str += genUsageSection("Project options:", list); 572 | } 573 | 574 | if (!depopts.isEmpty()) { 575 | list = optsToUsage(depopts); 576 | str += genUsageSection("Dependency options:", list); 577 | } 578 | 579 | str += "EOT\n}\n\n"; 580 | return str; 581 | } 582 | 583 | QString genUsageOutput() const 584 | { 585 | QString str = "Usage: $0 [OPTION]...\n\n" 586 | "This script creates necessary configuration files to build/install.\n\n"; 587 | 588 | QList list = optsToUsage(mainopts); 589 | list += ConfUsageOpt("verbose", "", "Show extra configure output."); 590 | list += ConfUsageOpt("qtselect", "N", "Select major Qt version (4 or 5)."); 591 | list += ConfUsageOpt("help", "", "This help text."); 592 | str += genUsageSection("Main options:", list); 593 | 594 | if (!appopts.isEmpty()) { 595 | list = optsToUsage(appopts); 596 | str += genUsageSection("Project options:", list); 597 | } 598 | 599 | if (!depopts.isEmpty()) { 600 | list = optsToUsage(depopts); 601 | str += genUsageSection("Dependency options:", list); 602 | } 603 | 604 | return str; 605 | } 606 | 607 | QString genFindStuff() 608 | { 609 | QString str; 610 | 611 | // which 612 | str += "# which/make detection adapted from Qt\n" 613 | "which_command() {\n" 614 | " ALL_MATCHES=\n" 615 | " if [ \"$1\" = \"-a\" ]; then\n" 616 | " ALL_MATCHES=\"-a\"\n" 617 | " shift\n" 618 | " fi\n" 619 | "\n" 620 | " OLD_HOME=$HOME\n" 621 | " HOME=/dev/null\n" 622 | " export HOME\n" 623 | "\n" 624 | " WHICH=`which which 2>/dev/null`\n" 625 | " if echo $WHICH | grep 'shell built-in command' >/dev/null 2>&1; then\n" 626 | " WHICH=which\n" 627 | " elif [ -z \"$WHICH\" ]; then\n" 628 | " if which which >/dev/null 2>&1; then\n" 629 | " WHICH=which\n" 630 | " else\n" 631 | " for a in /usr/ucb /usr/bin /bin /usr/local/bin; do\n" 632 | " if [ -x $a/which ]; then\n" 633 | " WHICH=$a/which\n" 634 | " break\n" 635 | " fi\n" 636 | " done\n" 637 | " fi\n" 638 | " fi\n" 639 | "\n" 640 | " RET_CODE=1\n" 641 | " if [ -z \"$WHICH\" ]; then\n" 642 | " OLD_IFS=$IFS\n" 643 | " IFS=:\n" 644 | " for a in $PATH; do\n" 645 | " if [ -x $a/$1 ]; then\n" 646 | " echo \"$a/$1\"\n" 647 | " RET_CODE=0\n" 648 | " [ -z \"$ALL_MATCHES\" ] && break\n" 649 | " fi\n" 650 | " done\n" 651 | " IFS=$OLD_IFS\n" 652 | " export IFS\n" 653 | " else\n" 654 | " a=`\"$WHICH\" \"$ALL_MATCHES\" \"$1\" 2>/dev/null`\n" 655 | " if [ ! -z \"$a\" -a -x \"$a\" ]; then\n" 656 | " echo \"$a\"\n" 657 | " RET_CODE=0\n" 658 | " fi\n" 659 | " fi\n" 660 | " HOME=$OLD_HOME\n" 661 | " export HOME\n" 662 | " return $RET_CODE\n" 663 | "}\n" 664 | "WHICH=which_command\n" 665 | "\n"; 666 | 667 | // make 668 | str += "# find a make command\n" 669 | "if [ -z \"$MAKE\" ]; then\n" 670 | " MAKE=\n" 671 | " for mk in gmake make; do\n" 672 | " if $WHICH $mk >/dev/null 2>&1; then\n" 673 | " MAKE=`$WHICH $mk`\n" 674 | " break\n" 675 | " fi\n" 676 | " done\n" 677 | " if [ -z \"$MAKE\" ]; then\n" 678 | " echo \"You don't seem to have 'make' or 'gmake' in your PATH.\"\n" 679 | " echo \"Cannot proceed.\"\n" 680 | " exit 1\n" 681 | " fi\n" 682 | "fi\n" 683 | "\n"; 684 | 685 | return str; 686 | } 687 | 688 | QString genQtInfo() 689 | { 690 | QString str = "show_qt_info() {\n"; 691 | str += echoBlock(1, qt4_info_str); 692 | str += "}\n\n"; 693 | return str; 694 | } 695 | 696 | QString genConfArg(const QString &name, const QString &var, bool arg = true) 697 | { 698 | QString str; 699 | if (arg) { 700 | str = QString(" --%1=*)\n" 701 | //" %2=`expr \"${1}\" : \"--%3=\\(.*\\)\"`\n" 702 | //" %2=\"${1#--%3=}\"\n" 703 | " %2=$optarg\n" 704 | " shift\n" 705 | " ;;\n" 706 | "\n") 707 | .arg(name) 708 | .arg(var); //.arg(name); 709 | } else { 710 | str = QString(" --%1)\n" 711 | " %2=\"Y\"\n" 712 | " shift\n" 713 | " ;;\n" 714 | "\n") 715 | .arg(name) 716 | .arg(var); 717 | } 718 | return str; 719 | } 720 | 721 | QString createConfArgsSection() 722 | { 723 | char argsheader[] = "while [ $# -gt 0 ]; do\n" 724 | " optarg=`expr \"x$1\" : 'x[^=]*=\\(.*\\)'`\n" 725 | " case \"$1\" in\n"; 726 | 727 | char argsfooter[] = " --verbose)\n" 728 | " QC_VERBOSE=\"Y\"\n" 729 | " shift\n" 730 | " ;;\n" 731 | " --qtselect=*)\n" 732 | " QC_QTSELECT=\"${optarg}\"\n" 733 | " shift\n" 734 | " ;;\n" 735 | " --help) show_usage; exit ;;\n" 736 | " *) echo \"configure: WARNING: unrecognized options: $1\" >&2; shift; ;;\n" 737 | " esac\n" 738 | "done\n\n"; 739 | 740 | QString str; 741 | str += argsheader; 742 | for (QList::ConstIterator it = mainopts.begin(); it != mainopts.end(); ++it) 743 | str += genConfArg((*it).name, (*it).var, !(*it).arg.isEmpty()); 744 | for (QList::ConstIterator it = appopts.begin(); it != appopts.end(); ++it) 745 | str += genConfArg((*it).name, (*it).var, !(*it).arg.isEmpty()); 746 | for (QList::ConstIterator it = depopts.begin(); it != depopts.end(); ++it) 747 | str += genConfArg((*it).name, (*it).var, !(*it).arg.isEmpty()); 748 | str += argsfooter; 749 | return str; 750 | } 751 | 752 | QString genQt4Checks() 753 | { 754 | QString str = "if [ -z \"$QC_QTSELECT\" ]; then\n" 755 | " QC_QTSELECT=\"$(echo $QT_SELECT | tr -d \"qt\")\"\n" 756 | "fi\n" 757 | "\n" 758 | "if [ ! -z \"$QC_QTSELECT\" ]; then\n" 759 | " QTSEARCHTEXT=\"$QC_QTSELECT\"\n" 760 | "else\n" 761 | " QTSEARCHTEXT=\"4 or 5\"\n" 762 | "fi\n" 763 | "\n" 764 | "# run qmake and check version\n" 765 | "qmake_check() {\n" 766 | " if [ -x \"$1\" ]; then\n" 767 | " cmd=\"\\\"$1\\\" -query QT_VERSION\"\n" 768 | " if [ \"$QC_VERBOSE\" = \"Y\" ]; then\n" 769 | " echo \"running: $cmd\"\n" 770 | " fi\n" 771 | " vout=`/bin/sh -c \"$cmd\" 2>&1`\n" 772 | " case \"${vout}\" in\n" 773 | " *.*.*)\n" 774 | " vmaj=\"${vout%%.*}\"\n" 775 | " if [ ! -z \"$QC_QTSELECT\" ]; then\n" 776 | " if [ \"$vmaj\" = \"$QC_QTSELECT\" ]; then\n" 777 | " return 0\n" 778 | " fi\n" 779 | " else\n" 780 | " if [ \"$vmaj\" = \"4\" ] || [ \"$vmaj\" = \"5\" ]; then\n" 781 | " return 0\n" 782 | " fi\n" 783 | " fi\n" 784 | " ;;\n" 785 | " esac\n" 786 | " if [ \"$QC_VERBOSE\" = \"Y\" ]; then\n" 787 | " echo \"Warning: $1 not for Qt ${QTSEARCHTEXT}\"\n" 788 | " fi\n" 789 | " fi\n" 790 | " return 1\n" 791 | "}\n" 792 | "\n"; 793 | 794 | str += "if [ \"$QC_VERBOSE\" = \"Y\" ]; then\n" 795 | " echo\n" 796 | "fi\n" 797 | "\n" 798 | "qm=\"\"\n" 799 | "qt4_names=\"qmake-qt4 qmake4\"\n" 800 | "qt5_names=\"qmake-qt5 qmake5\"\n" 801 | "names=\"qmake\"\n" 802 | "if [ -z \"$QC_QTSELECT\" ]; then\n" 803 | " names=\"${qt5_names} ${qt4_names} $names\"\n" 804 | "else\n" 805 | " if [ \"$QC_QTSELECT\" = \"4\" ]; then\n" 806 | " names=\"${qt4_names} $names\"\n" 807 | " elif [ \"$QC_QTSELECT\" -ge \"5\" ]; then\n" 808 | " names=\"${qt5_names} $names\"\n" 809 | " fi\n" 810 | "fi\n" 811 | "\n" 812 | "if [ -z \"$qm\" ] && [ ! -z \"$EX_QTDIR\" ]; then\n" 813 | " # qt4 check: --qtdir\n" 814 | " for n in $names; do\n" 815 | " qstr=$EX_QTDIR/bin/$n\n" 816 | " if qmake_check \"$qstr\"; then\n" 817 | " qm=$qstr\n" 818 | " break\n" 819 | " fi\n" 820 | " done\n" 821 | " if [ -z \"$qm\" ] && [ \"$QC_VERBOSE\" = \"Y\" ]; then\n" 822 | " echo \"Warning: qmake not found via --qtdir\"\n" 823 | " fi\n" 824 | "\n" 825 | "elif [ -z \"$qm\" ] && [ ! -z \"$QTDIR\" ]; then\n" 826 | " # qt4 check: QTDIR\n" 827 | " for n in $names; do\n" 828 | " qstr=$QTDIR/bin/$n\n" 829 | " if qmake_check \"$qstr\"; then\n" 830 | " qm=$qstr\n" 831 | " break\n" 832 | " fi\n" 833 | " done\n" 834 | " if [ -z \"$qm\" ] && [ \"$QC_VERBOSE\" = \"Y\" ]; then\n" 835 | " echo \"Warning: qmake not found via \\$QTDIR\"\n" 836 | " fi\n" 837 | "\n" 838 | "else\n" 839 | " # Try all other implicit checks\n" 840 | "\n" 841 | " # qtchooser\n" 842 | " if [ -z \"$qm\" ]; then\n" 843 | " qtchooser=$($WHICH qtchooser 2>/dev/null)\n" 844 | " if [ ! -z \"$qtchooser\" ]; then\n" 845 | " if [ ! -z \"$QC_QTSELECT\" ]; then\n" 846 | " versions=\"$QC_QTSELECT\"\n" 847 | " else\n" 848 | " cmd=\"$qtchooser --list-versions\"\n" 849 | " if [ \"$QC_VERBOSE\" = \"Y\" ]; then\n" 850 | " echo \"running: $cmd\"\n" 851 | " fi\n" 852 | " versions=`$cmd`\n" 853 | " fi\n" 854 | " for version in $versions; do\n" 855 | " cmd=\"$qtchooser -run-tool=qmake -qt=${version} -query " 856 | "QT_INSTALL_BINS\"\n" 857 | " if [ \"$QC_VERBOSE\" = \"Y\" ]; then\n" 858 | " echo \"running: $cmd\"\n" 859 | " fi\n" 860 | " qtbins=`$cmd 2>/dev/null`\n" 861 | " if [ ! -z \"$qtbins\" ] && qmake_check \"$qtbins/qmake\"; then\n" 862 | " qm=\"$qtbins/qmake\"\n" 863 | " break\n" 864 | " fi\n" 865 | " done\n" 866 | " fi\n" 867 | " fi\n" 868 | " if [ -z \"$qm\" ] && [ \"$QC_VERBOSE\" = \"Y\" ]; then\n" 869 | " echo \"Warning: qmake not found via qtchooser\"\n" 870 | " fi\n" 871 | "\n" 872 | " # qt4: pkg-config\n" 873 | " if [ -z \"$qm\" ]; then\n" 874 | " cmd=\"pkg-config QtCore --variable=exec_prefix\"\n" 875 | " if [ \"$QC_VERBOSE\" = \"Y\" ]; then\n" 876 | " echo \"running: $cmd\"\n" 877 | " fi\n" 878 | " str=`$cmd 2>/dev/null`\n" 879 | " if [ ! -z \"$str\" ]; then\n" 880 | " for n in $names; do\n" 881 | " qstr=$str/bin/$n\n" 882 | " if qmake_check \"$qstr\"; then\n" 883 | " qm=$qstr\n" 884 | " break\n" 885 | " fi\n" 886 | " done\n" 887 | " fi\n" 888 | " fi\n" 889 | " if [ -z \"$qm\" ] && [ \"$QC_VERBOSE\" = \"Y\" ]; then\n" 890 | " echo \"Warning: qmake not found via pkg-config\"\n" 891 | " fi\n" 892 | "\n" 893 | " # qmake in PATH\n" 894 | " if [ -z \"$qm\" ]; then\n" 895 | " for n in $names; do\n" 896 | " qstr=`$WHICH -a $n 2>/dev/null`\n" 897 | " for q in $qstr; do\n" 898 | " if qmake_check \"$q\"; then\n" 899 | " qm=\"$q\"\n" 900 | " break\n" 901 | " fi\n" 902 | " done\n" 903 | " if [ ! -z \"$qm\" ]; then\n" 904 | " break\n" 905 | " fi\n" 906 | " done\n" 907 | " fi\n" 908 | " if [ -z \"$qm\" ] && [ \"$QC_VERBOSE\" = \"Y\" ]; then\n" 909 | " echo \"Warning: qmake not found via \\$PATH\"\n" 910 | " fi\n" 911 | "\n" 912 | " # end of implicit checks\n" 913 | "fi\n" 914 | "\n" 915 | "if [ -z \"$qm\" ]; then\n" 916 | " if [ \"$QC_VERBOSE\" = \"Y\" ]; then\n" 917 | " echo \" -> fail\"\n" 918 | " else\n" 919 | " echo \"fail\"\n" 920 | " fi\n"; 921 | 922 | str += echoBlock(1, 923 | "\n" 924 | "Reason: Unable to find the 'qmake' tool for Qt ${QTSEARCHTEXT}.\n" 925 | "\n"); 926 | str += " show_qt_info\n"; 927 | str += " exit 1;\n" 928 | "fi\n" 929 | "if [ \"$QC_VERBOSE\" = \"Y\" ]; then\n" 930 | " echo qmake found in \"$qm\"\n" 931 | "fi\n\n"; 932 | 933 | str += "# try to determine the active makespec\n" 934 | "defmakespec=$QMAKESPEC\n" 935 | "if [ -z \"$defmakespec\" ]; then\n" 936 | " if $WHICH readlink >/dev/null 2>&1; then\n" 937 | " READLINK=`$WHICH readlink`\n" 938 | " fi\n" 939 | " if [ ! -z \"$READLINK\" ]; then\n" 940 | " qt_mkspecsdir=`\"$qm\" -query QT_INSTALL_DATA`/mkspecs\n" 941 | " if [ -d \"$qt_mkspecsdir\" ] && [ -h \"$qt_mkspecsdir/default\" ]; then\n" 942 | " defmakespec=`$READLINK $qt_mkspecsdir/default`\n" 943 | " fi\n" 944 | " fi\n" 945 | "fi\n" 946 | "\n" 947 | "if [ \"$QC_VERBOSE\" = \"Y\" ]; then\n" 948 | " echo makespec is $defmakespec\n" 949 | "fi\n" 950 | "\n" 951 | "qm_spec=\"\"\n" 952 | "# if the makespec is macx-xcode, force macx-g++\n" 953 | "if [ \"$defmakespec\" = \"macx-xcode\" ]; then\n" 954 | " qm_spec=macx-g++\n" 955 | " QMAKESPEC=$qm_spec\n" 956 | " export QMAKESPEC\n" 957 | " if [ \"$QC_VERBOSE\" = \"Y\" ]; then\n" 958 | " echo overriding makespec to $qm_spec\n" 959 | " fi\n" 960 | "fi\n\n"; 961 | 962 | return str; 963 | } 964 | 965 | QString genDoQConf() 966 | { 967 | QString outdir = ".qconftemp"; 968 | QString cleanup = QString("rm -rf \"%1\"").arg(outdir); 969 | 970 | QString str; 971 | str += QString("%1\n").arg(cleanup); 972 | 973 | str += QString("(\n" 974 | " mkdir \"%1\"\n" 975 | " gen_files \"%2\"\n" 976 | " cd \"%3\"\n") 977 | .arg(outdir) 978 | .arg(outdir) 979 | .arg(outdir); 980 | 981 | if (qt4) { 982 | str += " if [ ! -z \"$qm_spec\" ]; then\n" 983 | " \"$qm\" -spec $qm_spec conf4.pro >/dev/null\n" 984 | " else\n" 985 | " \"$qm\" conf4.pro >/dev/null\n" 986 | " fi\n" 987 | " $MAKE clean >/dev/null 2>&1\n" 988 | " $MAKE >../conf.log 2>&1\n"; 989 | } 990 | str += ")\n\n"; 991 | 992 | if (qt4) { 993 | str += QString("if [ \"$?\" != \"0\" ]; then\n" 994 | " %1\n" 995 | " if [ \"$QC_VERBOSE\" = \"Y\" ]; then\n" 996 | " echo \" -> fail\"\n" 997 | " else\n" 998 | " echo \"fail\"\n" 999 | " fi\n") 1000 | .arg(cleanup); 1001 | 1002 | str += echoBlock(1, 1003 | "\n" 1004 | "Reason: There was an error compiling 'conf'. See conf.log for details.\n" 1005 | "\n"); 1006 | if (!byoq) { 1007 | str += " show_qt_info\n"; 1008 | } 1009 | 1010 | str += " if [ \"$QC_VERBOSE\" = \"Y\" ]; then\n" 1011 | " echo \"conf.log:\"\n" 1012 | " cat conf.log\n" 1013 | " fi\n"; 1014 | 1015 | str += " exit 1;\n" 1016 | "fi\n\n"; 1017 | } 1018 | 1019 | if (qt4) { 1020 | str += QString("QC_COMMAND=$0\n"); 1021 | str += QString("export QC_COMMAND\n"); 1022 | str += QString("QC_PROFILE=%1\n").arg(profile); 1023 | str += QString("export QC_PROFILE\n"); 1024 | str += QString("QC_QMAKE=\"$qm\"\n"); 1025 | str += QString("export QC_QMAKE\n"); 1026 | str += QString("QC_QMAKESPEC=$qm_spec\n"); 1027 | str += QString("export QC_QMAKESPEC\n"); 1028 | str += QString("QC_MAKETOOL=$MAKE\n"); 1029 | str += QString("export QC_MAKETOOL\n"); 1030 | } 1031 | 1032 | str += QString("\"%1/conf\"\n").arg(outdir); 1033 | 1034 | str += "ret=\"$?\"\n"; 1035 | str += "if [ \"$ret\" = \"1\" ]; then\n"; 1036 | str += QString(" %1\n").arg(cleanup); 1037 | str += " echo\n"; 1038 | str += " exit 1;\n"; 1039 | str += "else\n"; 1040 | str += " if [ \"$ret\" != \"0\" ]; then\n"; 1041 | str += QString(" %1\n").arg(cleanup); 1042 | 1043 | if (qt4) { 1044 | str += " if [ \"$QC_VERBOSE\" = \"Y\" ]; then\n" 1045 | " echo \" -> fail\"\n" 1046 | " else\n" 1047 | " echo \"fail\"\n" 1048 | " fi\n"; 1049 | } 1050 | 1051 | str += " echo\n"; 1052 | if (qt4) 1053 | str += " echo \"Reason: Unexpected error launching 'conf'\"\n"; 1054 | str += " echo\n"; 1055 | str += " exit 1;\n"; 1056 | str += " fi\n"; 1057 | str += "fi\n"; 1058 | str += QString("%1\n\n").arg(cleanup); 1059 | 1060 | return str; 1061 | } 1062 | 1063 | QString genRunExtra() 1064 | { 1065 | QString str = "if [ -x \"./qcextra\" ]; then\n" 1066 | " ./qcextra\n" 1067 | "fi\n"; 1068 | return str; 1069 | } 1070 | 1071 | QString genRunQMake() 1072 | { 1073 | QString str; 1074 | str += "# run qmake\n"; 1075 | str += QString("\"$qm\" %1\n").arg(profile); 1076 | str += "if [ \"$?\" != \"0\" ]; then\n" 1077 | " echo\n" 1078 | " exit 1;\n" 1079 | "fi\n"; 1080 | 1081 | if (!qt4) { 1082 | str += "cat >Makefile.tmp <> Makefile.tmp\n" 1087 | "rm -f Makefile\n" 1088 | "cp -f Makefile.tmp Makefile\n" 1089 | "rm -f Makefile.tmp\n"; 1090 | } 1091 | 1092 | str += "\n"; 1093 | 1094 | return str; 1095 | } 1096 | 1097 | QString genEmbeddedFile(const QString &name, const QByteArray &a) 1098 | { 1099 | QString str; 1100 | str += QString("cat >\"%1\" < args; 1176 | 1177 | static QCModInfo getModInfo(const QByteArray &buf) 1178 | { 1179 | QCModInfo info; 1180 | QStringList lines = getQCMODLines(buf); 1181 | for (QStringList::ConstIterator it = lines.begin(); it != lines.end(); ++it) { 1182 | const QString &line = *it; 1183 | int n = line.indexOf(':'); 1184 | if (n == -1) 1185 | continue; 1186 | QString type = line.mid(0, n).toLower(); 1187 | // find next non-whitespace 1188 | ++n; 1189 | for (; n < (int)line.length(); ++n) { 1190 | if (!line[n].isSpace()) 1191 | break; 1192 | } 1193 | QString rest = line.mid(n); 1194 | 1195 | if (type == "name") { 1196 | info.longname = rest; 1197 | } else if (type == "section") { 1198 | info.section = rest; 1199 | } else if (type == "arg") { 1200 | QString name, arg, desc; 1201 | if (!parseArg(rest, &name, &arg, &desc)) 1202 | continue; 1203 | QCModArg a; 1204 | a.name = name; 1205 | a.arg = arg; 1206 | a.desc = desc; 1207 | info.args += a; 1208 | } 1209 | } 1210 | 1211 | return info; 1212 | } 1213 | }; 1214 | 1215 | enum VersionMode { VersionMin, VersionExact, VersionMax, VersionAny }; 1216 | 1217 | class Dep { 1218 | public: 1219 | Dep() 1220 | { 1221 | pkgvermode = VersionMode::VersionAny; 1222 | required = false; 1223 | disabled = false; 1224 | pkgconfig = false; 1225 | } 1226 | 1227 | QString name, longname, section; 1228 | bool required; 1229 | bool disabled; 1230 | QList args; 1231 | 1232 | bool pkgconfig; 1233 | QString pkgname; 1234 | VersionMode pkgvermode; 1235 | QString pkgver; 1236 | }; 1237 | 1238 | class Conf { 1239 | public: 1240 | Conf() 1241 | { 1242 | libmode = false; 1243 | noprefix = false; 1244 | nobindir = false; 1245 | useincdir = false; 1246 | uselibdir = false; 1247 | usedatadir = false; 1248 | qt4 = false; 1249 | byoq = false; 1250 | } 1251 | 1252 | QString name, profile; 1253 | QList deps; 1254 | QList args; 1255 | bool libmode, noprefix, nobindir, useincdir, uselibdir, usedatadir; 1256 | QStringList moddirs; 1257 | bool qt4, byoq; 1258 | }; 1259 | 1260 | Conf xmlToConf(const QDomElement &e) 1261 | { 1262 | Conf conf; 1263 | conf.name = e.elementsByTagName("name").item(0).toElement().text(); 1264 | 1265 | conf.profile = e.elementsByTagName("profile").item(0).toElement().text(); 1266 | 1267 | QDomNodeList nl = e.elementsByTagName("dep"); 1268 | for (int n = 0; n < (int)nl.count(); ++n) { 1269 | QDomElement i = nl.item(n).toElement(); 1270 | Dep dep; 1271 | dep.name = i.attribute("type"); 1272 | if (dep.name == "pkg") { 1273 | dep.name = i.attribute("name"); 1274 | dep.longname = dep.name; 1275 | dep.pkgconfig = true; 1276 | dep.pkgname = i.attribute("pkgname"); 1277 | QString str = i.attribute("version"); 1278 | VersionMode mode = VersionAny; 1279 | QString ver; 1280 | if (str.startsWith(">=")) { 1281 | mode = VersionMin; 1282 | ver = str.mid(2); 1283 | } else if (str.startsWith("<=")) { 1284 | mode = VersionMax; 1285 | ver = str.mid(2); 1286 | } else if (!str.isEmpty()) { 1287 | mode = VersionExact; 1288 | ver = str; 1289 | } 1290 | dep.pkgvermode = mode; 1291 | dep.pkgver = ver; 1292 | } 1293 | if (i.elementsByTagName("required").count() > 0) 1294 | dep.required = true; 1295 | if (i.elementsByTagName("disabled").count() > 0) 1296 | dep.disabled = true; 1297 | conf.deps += dep; 1298 | } 1299 | 1300 | nl = e.elementsByTagName("arg"); 1301 | for (int n = 0; n < (int)nl.count(); ++n) { 1302 | QDomElement i = nl.item(n).toElement(); 1303 | QCModArg a; 1304 | a.name = i.attribute("name"); 1305 | a.arg = i.attribute("arg"); 1306 | a.desc = i.text(); 1307 | conf.args += a; 1308 | } 1309 | 1310 | if (e.elementsByTagName("lib").count() > 0) 1311 | conf.libmode = true; 1312 | 1313 | if (e.elementsByTagName("noprefix").count() > 0) 1314 | conf.noprefix = true; 1315 | 1316 | if (e.elementsByTagName("nobindir").count() > 0) 1317 | conf.nobindir = true; 1318 | 1319 | if (e.elementsByTagName("incdir").count() > 0) 1320 | conf.useincdir = true; 1321 | 1322 | if (e.elementsByTagName("libdir").count() > 0) 1323 | conf.uselibdir = true; 1324 | 1325 | if (e.elementsByTagName("datadir").count() > 0) 1326 | conf.usedatadir = true; 1327 | 1328 | nl = e.elementsByTagName("moddir"); 1329 | for (int n = 0; n < (int)nl.count(); ++n) { 1330 | QDomElement i = nl.item(n).toElement(); 1331 | conf.moddirs += i.text(); 1332 | } 1333 | 1334 | conf.qt4 = true; 1335 | if (e.elementsByTagName("qt3").count() > 0) 1336 | conf.qt4 = false; 1337 | 1338 | if (conf.qt4 && e.elementsByTagName("byoq").count() > 0) 1339 | conf.byoq = true; 1340 | 1341 | return conf; 1342 | } 1343 | 1344 | int main(int argc, char **argv) 1345 | { 1346 | QCoreApplication app(argc, argv); 1347 | Conf conf; 1348 | QString fname; 1349 | bool skipLoad = false; 1350 | 1351 | if (argc < 2) { 1352 | // try to find a .qc file 1353 | QDir cur; 1354 | QStringList list = cur.entryList(QStringList() << "*.qc"); 1355 | if (list.isEmpty()) { 1356 | // try to find a .pro file to work from 1357 | list = cur.entryList(QStringList() << "*.pro"); 1358 | if (list.isEmpty()) { 1359 | printf("qconf: no .qc or .pro file found.\n"); 1360 | return 1; 1361 | } 1362 | QFileInfo fi(cur.filePath(list[0])); 1363 | conf.name = fi.baseName(); 1364 | conf.profile = fi.fileName(); 1365 | 1366 | // save to .qc 1367 | fname = conf.name + ".qc"; 1368 | QFile f(fname); 1369 | if (!f.open(QFile::WriteOnly | QFile::Truncate)) { 1370 | printf("qconf: unable to write %s\n", qPrintable(fname)); 1371 | return 1; 1372 | } 1373 | QDomDocument doc; 1374 | QDomElement e = doc.createElement("qconf"); 1375 | QDomElement i; 1376 | i = doc.createElement("name"); 1377 | i.appendChild(doc.createTextNode(conf.name)); 1378 | e.appendChild(i); 1379 | i = doc.createElement("profile"); 1380 | i.appendChild(doc.createTextNode(conf.profile)); 1381 | e.appendChild(i); 1382 | doc.appendChild(e); 1383 | QByteArray cs = doc.toString().toUtf8(); 1384 | f.write(cs); 1385 | f.close(); 1386 | skipLoad = true; 1387 | } else { 1388 | fname = list[0]; 1389 | } 1390 | } else { 1391 | QString cs = argv[1]; 1392 | if (cs.left(2) == "--") { 1393 | if (cs == "--help") { 1394 | printf("Usage: qconf [.qc file]\n\n"); 1395 | printf("Options:\n"); 1396 | printf(" --version Show version number\n"); 1397 | printf(" --help This help\n"); 1398 | printf("\n"); 1399 | return 0; 1400 | } else if (cs == "--version") { 1401 | printf("qconf version: %s by Psi IM Team\n", VERSION); 1402 | return 0; 1403 | } else { 1404 | printf("Unknown option: %s\n", qPrintable(cs)); 1405 | return 0; 1406 | } 1407 | } 1408 | fname = QFile::decodeName(QByteArray(argv[1])); 1409 | } 1410 | 1411 | if (!skipLoad) { 1412 | QFile f(fname); 1413 | if (!f.open(QFile::ReadOnly)) { 1414 | printf("qconf: error reading %s\n", qPrintable(f.fileName())); 1415 | return 1; 1416 | } 1417 | QDomDocument doc; 1418 | if (!doc.setContent(&f)) { 1419 | printf("qconf: error parsing %s\n", qPrintable(f.fileName())); 1420 | return 1; 1421 | } 1422 | f.close(); 1423 | 1424 | QDomElement base = doc.documentElement(); 1425 | if (base.tagName() != "qconf") { 1426 | printf("qconf: bad format of %s\n", qPrintable(f.fileName())); 1427 | return 1; 1428 | } 1429 | conf = xmlToConf(base); 1430 | } 1431 | 1432 | // see if the appdir looks like an in-place qconf build 1433 | QString appdir = QCoreApplication::applicationDirPath(); 1434 | QString localDataPath; 1435 | if (looksLikeInPlace(appdir)) 1436 | localDataPath = appdir; 1437 | 1438 | QStringList moddirs; 1439 | if (!conf.moddirs.isEmpty()) 1440 | moddirs += conf.moddirs; 1441 | 1442 | QString confdirpath; 1443 | if (!localDataPath.isEmpty()) { 1444 | moddirs += localDataPath + "/modules"; 1445 | confdirpath = localDataPath + "/conf"; 1446 | } else { 1447 | #ifdef DATADIR 1448 | moddirs += QString(DATADIR) + "/qconf/modules"; 1449 | confdirpath = QString(DATADIR) + "/qconf/conf"; 1450 | #else 1451 | moddirs += "./modules"; 1452 | confdirpath = "./conf"; 1453 | #endif 1454 | } 1455 | 1456 | QDir confdir(confdirpath); 1457 | if (!confdir.exists()) { 1458 | #ifdef Q_OS_WIN 1459 | confdir = QDir(appdir + "/../share/qconf/conf"); 1460 | if (!confdir.exists()) { 1461 | #endif 1462 | printf("qconf: %s does not exist.\n", qPrintable(confdir.absolutePath())); 1463 | return 1; 1464 | #ifdef Q_OS_WIN 1465 | } 1466 | #endif 1467 | } 1468 | 1469 | QFile f; 1470 | QByteArray confh; 1471 | if (conf.qt4) { 1472 | f.setFileName(confdir.filePath("conf4.h")); 1473 | if (!f.open(QFile::ReadOnly)) { 1474 | printf("qconf: cannot read %s\n", qPrintable(f.fileName())); 1475 | return 1; 1476 | } 1477 | confh = f.readAll(); 1478 | f.close(); 1479 | } 1480 | 1481 | f.setFileName(confdir.filePath(conf.qt4 ? "conf4.cpp" : "conf.cpp")); 1482 | if (!f.open(QFile::ReadOnly)) { 1483 | printf("qconf: cannot read %s\n", qPrintable(f.fileName())); 1484 | return 1; 1485 | } 1486 | QByteArray confcpp = f.readAll(); 1487 | f.close(); 1488 | 1489 | f.setFileName(confdir.filePath(conf.qt4 ? "conf4.pro" : "conf.pro")); 1490 | if (!f.open(QFile::ReadOnly)) { 1491 | printf("qconf: cannot read %s\n", qPrintable(f.fileName())); 1492 | return 1; 1493 | } 1494 | QByteArray confpro = f.readAll(); 1495 | f.close(); 1496 | confpro += "\nDEFINES += HAVE_MODULES\n"; 1497 | confpro += "\ngreaterThan(QT_MAJOR_VERSION, 4):CONFIG += c++11\n"; 1498 | 1499 | printf("Project name: %s\n", qPrintable(conf.name)); 1500 | printf("Profile: %s\n", qPrintable(conf.profile)); 1501 | printf("Deps: "); 1502 | if (conf.deps.isEmpty()) 1503 | printf("none\n"); 1504 | else { 1505 | bool first = true; 1506 | for (QList::ConstIterator it = conf.deps.begin(); it != conf.deps.end(); ++it) { 1507 | const Dep &dep = *it; 1508 | printf("%s%s%s", first ? "" : " ", qPrintable(dep.name), dep.required ? "*" : ""); 1509 | first = false; 1510 | } 1511 | printf("\n"); 1512 | } 1513 | printf("\n"); 1514 | 1515 | // look up dep module information 1516 | QByteArray allmods; 1517 | QString modscreate; 1518 | for (QList::Iterator it = conf.deps.begin(); it != conf.deps.end(); ++it) { 1519 | Dep &dep = *it; 1520 | 1521 | if (dep.pkgconfig) { 1522 | QString desc = dep.longname; 1523 | QString modestr = "VersionAny"; 1524 | if (dep.pkgvermode != VersionAny) { 1525 | if (dep.pkgvermode == VersionMin) { 1526 | desc += " >= "; 1527 | modestr = "VersionMin"; 1528 | } else if (dep.pkgvermode == VersionMax) { 1529 | desc += " <= "; 1530 | modestr = "VersionMax"; 1531 | } else { 1532 | desc += " "; 1533 | modestr = "VersionExact"; 1534 | } 1535 | desc += dep.pkgver; 1536 | } 1537 | modscreate += QString(" o = new qc_internal_pkgconfig(conf, \"%1\", \"%2\", %3, \"%4\");\n " 1538 | "o->required = %5;\n o->disabled = %6;\n") 1539 | .arg(dep.pkgname) 1540 | .arg(desc) 1541 | .arg(modestr) 1542 | .arg(dep.pkgver) 1543 | .arg(dep.required ? "true" : "false") 1544 | .arg(dep.disabled ? "true" : "false"); 1545 | continue; 1546 | } 1547 | 1548 | // look for module 1549 | QString modfname = QString("%1.qcm").arg(dep.name); 1550 | QFileInfo fi; 1551 | bool found = false; 1552 | for (QStringList::ConstIterator mit = moddirs.begin(); mit != moddirs.end(); ++mit) { 1553 | QDir moddir(*mit); 1554 | fi.setFile(moddir.filePath(modfname)); 1555 | // printf("checking for: [%s]\n", fi.filePath().latin1()); 1556 | if (fi.exists()) { 1557 | found = true; 1558 | break; 1559 | } 1560 | } 1561 | if (!found) { 1562 | printf("qconf: no such module '%s'!\n", qPrintable(dep.name)); 1563 | return 1; 1564 | } 1565 | QFile mod(fi.filePath()); 1566 | if (!mod.open(QFile::ReadOnly | QFile::Text)) { 1567 | printf("qconf: error opening '%s'!\n", qPrintable(mod.fileName())); 1568 | return 1; 1569 | } 1570 | QByteArray buf = mod.readAll(); 1571 | mod.close(); 1572 | 1573 | QCModInfo info = QCModInfo::getModInfo(buf); 1574 | dep.longname = info.longname; 1575 | dep.section = info.section; 1576 | dep.args = info.args; 1577 | 1578 | allmods += (QString("#line 1 \"%1\"\n").arg(modfname).toLocal8Bit() + buf); 1579 | 1580 | modscreate += QString(" o = new qc_%1(conf);\n o->required = %2;\n o->disabled = %3;\n") 1581 | .arg(escapeArg(dep.name)) 1582 | .arg(dep.required ? "true" : "false") 1583 | .arg(dep.disabled ? "true" : "false"); 1584 | } 1585 | QByteArray modsnew = modscreate.toLatin1(); 1586 | 1587 | // write configure 1588 | QFile out; 1589 | out.setFileName("configure"); 1590 | if (!out.open(QFile::WriteOnly | QFile::Truncate)) { 1591 | printf("qconf: error writing configure\n"); 1592 | return 1; 1593 | } 1594 | ConfGen cg; 1595 | cg.name = conf.name; 1596 | cg.profile = conf.profile; 1597 | if (conf.libmode) 1598 | cg.libmode = true; 1599 | if (conf.noprefix) 1600 | cg.usePrefix = false; 1601 | if (conf.nobindir) 1602 | cg.useBindir = false; 1603 | if (conf.useincdir) 1604 | cg.useIncdir = true; 1605 | if (conf.uselibdir) 1606 | cg.useLibdir = true; 1607 | if (conf.usedatadir) 1608 | cg.useDatadir = true; 1609 | if (conf.qt4) 1610 | cg.qt4 = true; 1611 | if (conf.byoq) 1612 | cg.byoq = true; 1613 | cg.filemodulescpp = allmods; 1614 | cg.filemodulesnewcpp = modsnew; 1615 | cg.fileconfh = confh; 1616 | cg.fileconfcpp = confcpp; 1617 | cg.fileconfpro = confpro; 1618 | 1619 | for (QList::Iterator it = conf.deps.begin(); it != conf.deps.end(); ++it) { 1620 | Dep & dep = *it; 1621 | QString longname; 1622 | if (!dep.longname.isEmpty()) 1623 | longname = dep.longname; 1624 | else 1625 | longname = dep.name; 1626 | if (!dep.required && !dep.disabled) { 1627 | cg.addOption(dep.section, QString("disable-") + dep.name, "", QString("QC_DISABLE_") + escapeArg(dep.name), 1628 | QString("Disable use of ") + longname); 1629 | cg.addOption(dep.section, QString("enable-") + dep.name, "", 1630 | QString("QC_DEFAULT_ENABLE_") + escapeArg(dep.name)); 1631 | } else if (dep.disabled) { 1632 | cg.addOption(dep.section, QString("enable-") + dep.name, "", QString("QC_ENABLE_") + escapeArg(dep.name), 1633 | QString("Enable use of ") + longname); 1634 | cg.addOption(dep.section, QString("disable-") + dep.name, "", 1635 | QString("QC_DEFAULT_DISABLE_") + escapeArg(dep.name)); 1636 | } 1637 | 1638 | // extra dep args? 1639 | for (QList::ConstIterator ait = dep.args.begin(); ait != dep.args.end(); ++ait) { 1640 | const QCModArg &a = *ait; 1641 | cg.addOption(dep.section, a.name, a.arg, QString("QC_") + escapeArg(a.name.toUpper()), a.desc); 1642 | } 1643 | } 1644 | 1645 | // extra .qc args? 1646 | for (QList::ConstIterator it = conf.args.begin(); it != conf.args.end(); ++it) { 1647 | const QCModArg &a = *it; 1648 | cg.addAppOption(a.name, a.arg, QString("QC_") + escapeArg(a.name.toUpper()), a.desc); 1649 | } 1650 | 1651 | QByteArray cs = cg.generate(); 1652 | out.write(cs); 1653 | out.close(); 1654 | #ifdef Q_OS_UNIX 1655 | chmod("configure", 0755); 1656 | #endif 1657 | 1658 | printf("'configure' written.\n"); 1659 | 1660 | if (conf.qt4) { 1661 | // write configexe 1662 | out.setFileName("configure.exe"); 1663 | if (!out.open(QFile::WriteOnly | QFile::Truncate)) { 1664 | printf("qconf: error writing configure.exe\n"); 1665 | return 1; 1666 | } 1667 | cs = cg.generateExe(); 1668 | out.write(cs); 1669 | out.close(); 1670 | 1671 | printf("'configure.exe' written.\n"); 1672 | } 1673 | 1674 | return 0; 1675 | } 1676 | --------------------------------------------------------------------------------