├── 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 |
--------------------------------------------------------------------------------