configure: actually resolve libraries into full filepaths

this considerably speeds up failures, as no doomed build is attempted,
and produces more reliable results, as no second lookup (which would be
subject to environment changes) is done any more during the build.

in principle, this also opens up possibilities like selecting specific
variants of dependencies, automatically extracting rpaths, etc.

qt_helper_lib.prf also needs to create fully resolved library names now.

Change-Id: I65f13564b635433030e40fa017427bbc72d1c130
Reviewed-by: Joerg Bornemann <joerg.bornemann@qt.io>
This commit is contained in:
Oswald Buddenhagen 2017-12-01 20:13:08 +01:00
parent 46a2b44b2b
commit 521a85395d
7 changed files with 173 additions and 77 deletions

View File

@ -211,7 +211,7 @@
"verifySpec": [ "shared", "use_gold_linker", "compiler-flags", "qmakeargs", "commit" ],
"compile": [ "verifyspec" ],
"detectPkgConfig": [ "cross_compile", "machineTuple" ],
"library": [ "pkg-config" ],
"library": [ "pkg-config", "compiler-flags" ],
"getPkgConfigVariable": [ "pkg-config" ]
},

View File

@ -9,7 +9,6 @@ for(ever) {
error("Library '$$name' is not defined.")
!contains(use, nolink) {
QMAKE_LIBDIR += $$eval(QMAKE_LIBDIR_$$nu)
debug: \
LIBS$${suffix} += $$eval(QMAKE_LIBS_$${nu}_DEBUG) $$eval(QMAKE_LIBS_$$nu)
else: \

View File

@ -365,9 +365,13 @@ defineTest(qtConfTest_linkerSupportsFlag) {
}
defineReplace(qtConfFindInPathList) {
# This nesting is consistent with Apple ld -search_paths_first,
# and presumably with GNU ld (no actual documentation found).
for (dir, 2) {
exists("$$dir/$${1}"): \
return("$$dir/$${1}")
for (file, 1) {
exists("$$dir/$$file"): \
return("$$dir/$$file")
}
}
return()
}
@ -488,6 +492,110 @@ defineTest(qtConfSetupLibraries) {
}
}
# libs-var, libs, in-paths, out-paths-var
defineTest(qtConfResolveLibs) {
ret = true
paths = $$3
out =
copy = false
for (l, 2) {
$$copy {
copy = false
out += $$l
} else: equals(l, "-s") {
# em++ flag to link libraries from emscripten-ports; passed on literally.
copy = true
out += $$l
} else: contains(l, "^-L.*") {
lp = $$replace(l, "^-L", )
!exists($$lp/.) {
qtLog("Library path $$val_escape(lp) is invalid.")
ret = false
} else {
paths += $$lp
}
} else: contains(l, "^-l.*") {
lib = $$replace(l, "^-l", )
lcan =
unix {
# Under UNIX, we look for actual shared libraries, in addition
# to static ones.
lcan += \
$${QMAKE_PREFIX_SHLIB}$${lib}.$${QMAKE_EXTENSION_SHLIB} \
$${QMAKE_PREFIX_STATICLIB}$${lib}.$${QMAKE_EXTENSION_STATICLIB}
} else {
# Under Windows, we look only for static libraries, as even for DLLs
# one actually links against a static import library.
mingw {
lcan += \
# MinGW supports UNIX-style library naming in addition to
# the MSVC style.
lib$${lib}.dll.a lib$${lib}.a \
# Fun fact: prefix-less libraries are also supported.
$${lib}.dll.a $${lib}.a
}
lcan += $${lib}.lib
}
l = $$qtConfFindInPathList($$lcan, $$paths $$EXTRA_LIBDIR $$QMAKE_DEFAULT_LIBDIRS)
isEmpty(l) {
qtLog("None of [$$val_escape(lcan)] found in [$$val_escape(paths)] and global paths.")
ret = false
} else {
out += $$l
}
} else {
out += $$l
}
}
$$1 = $$out
export($$1)
!isEmpty(4) {
$$4 = $$paths
export($$4)
}
return($$ret)
}
# source-var
defineTest(qtConfResolveAllLibs) {
ret = true
!qtConfResolveLibs($${1}.libs, $$eval($${1}.libs), , $${1}.libdirs): \
ret = false
for (b, $${1}.builds._KEYS_): \
!qtConfResolveLibs($${1}.builds.$${b}, $$eval($${1}.builds.$${b}), $$eval($${1}.libdirs), ): \
ret = false
return($$ret)
}
# libs-var, in-paths, libs
defineTest(qtConfResolvePathLibs) {
ret = true
for (libdir, 2) {
!exists($$libdir/.) {
qtLog("Library path $$val_escape(libdir) is invalid.")
ret = false
}
}
!qtConfResolveLibs($$1, $$3, $$2): \
ret = false
return($$ret)
}
# includes-var, includes
defineTest(qtConfResolvePathIncs) {
ret = true
for (incdir, 2) {
!exists($$incdir/.) {
qtLog("Include path $$val_escape(incdir) is invalid.")
ret = false
}
}
2 -= $$QMAKE_DEFAULT_INCDIRS
$$1 = $$2
export($$1)
return($$ret)
}
# the library is specified inline in a 'libs' field.
# overrides from the command line are accepted.
defineTest(qtConfLibrary_inline) {
@ -517,7 +625,6 @@ defineTest(qtConfLibrary_inline) {
vars += $$eval(config.commandline.rev_assignments.$${iv})
defined(config.input.$${iv}, var) {
eval($${1}.builds.$${b} = $$eval(config.input.$${iv}))
export($${1}.builds.$${b})
$${1}.builds._KEYS_ *= $${b}
any = true
} else {
@ -532,35 +639,30 @@ defineTest(qtConfLibrary_inline) {
export($${1}.builds._KEYS_)
# we also reset the generic libs, to avoid surprises.
$${1}.libs =
export($${1}.libs)
}
# direct libs. overwrites inline libs.
defined(config.input.$${input}.libs, var) {
defined(config.input.$${input}.libs, var): \
eval($${1}.libs = $$eval(config.input.$${input}.libs))
export($${1}.libs)
}
includes = $$eval(config.input.$${input}.incdir)
# prefix. prepends to (possibly overwritten) inline libs.
prefix = $$eval(config.input.$${input}.prefix)
!isEmpty(prefix) {
$${1}.includedir = $$prefix/include
export($${1}.includedir)
includes += $$prefix/include
$${1}.libs = -L$$prefix/lib $$eval($${1}.libs)
export($${1}.libs)
}
incdir = $$eval(config.input.$${input}.incdir)
!isEmpty(incdir) {
$${1}.includedir = $$incdir
export($${1}.includedir)
}
libdir = $$eval(config.input.$${input}.libdir)
!isEmpty(libdir) {
!isEmpty(libdir): \
$${1}.libs = -L$$libdir $$eval($${1}.libs)
export($${1}.libs)
}
!qtConfResolveAllLibs($$1): \
return(false)
!qtConfResolvePathIncs($${1}.includedir, $$includes): \
return(false)
return(true)
}
@ -572,17 +674,13 @@ defineTest(qtConfLibrary_makeSpec) {
isEmpty(spec): \
error("makeSpec source in library '$$eval($${1}.library)' does not specify 'spec'.")
$${1}.includedir = $$eval(QMAKE_INCDIR_$$spec)
export($${1}.includedir)
$${1}.libs =
for (l, QMAKE_LIBDIR_$$spec): \
$${1}.libs += -L$$l
$${1}.libs += $$eval(QMAKE_LIBS_$$spec)
export($${1}.libs)
!qtConfResolvePathLibs($${1}.libs, $$eval(QMAKE_LIBDIR_$$spec), $$eval(QMAKE_LIBS_$$spec)): \
return(false)
# the library definition is always in scope, so no point in exporting it.
$${1}.export = false
export($${1}.export)
!qtConfResolvePathIncs($${1}.includedir, $$eval(QMAKE_INCDIR_$$spec)): \
return(false)
# note that the object is re-exported, because we resolve the libraries.
return(true)
}
@ -602,13 +700,15 @@ defineTest(qtConfLibrary_pkgConfig) {
}
qtRunLoggedCommand("$$pkg_config --modversion $$args", version)|return(false)
qtRunLoggedCommand("$$pkg_config --libs-only-L $$args", libpaths)|return(false)
qtRunLoggedCommand("$$pkg_config --libs-only-l $$args", libs)|return(false)
version ~= s/[^0-9.].*$//
$${1}.version = $$first(version)
export($${1}.version)
eval($${1}.libs = $$libpaths $$libs)
export($${1}.libs)
qtRunLoggedCommand("$$pkg_config --libs-only-L $$args", libpaths)|return(false)
qtRunLoggedCommand("$$pkg_config --libs-only-l $$args", libs)|return(false)
eval(libs = $$libpaths $$libs)
!qtConfResolveLibs($${1}.libs, $$libs): \
return(false)
qtRunLoggedCommand("$$pkg_config --cflags $$args", $${1}.cflags)|return(false)
# Split CFLAGS into stuff that goes into DEFINES, INCLUDEPATH, and other stuff.
@ -633,10 +733,11 @@ defineTest(qtConfLibrary_pkgConfig) {
}
!isEmpty(ignored): \
qtLog("Note: Dropped compiler flags '$$ignored'.")
!qtConfResolvePathIncs($${1}.includedir, $$includes): \
return(false)
$${1}.defines = $$defines
export($${1}.defines)
$${1}.includedir = $$includes
export($${1}.includedir)
return(true)
}

View File

@ -34,19 +34,30 @@ THE_TARGET = $$qt5LibraryTarget($$TARGET)
MODULE_PRI = $$MODULE_QMAKE_OUTDIR/mkspecs/modules/qt_ext_$${MODULE}.pri
ucmodule = $$upper($$MODULE)
win32|CONFIG(static, static|shared) {
prefix = $$QMAKE_PREFIX_STATICLIB
suffix = $$QMAKE_EXTENSION_STATICLIB
} else {
prefix = $$QMAKE_PREFIX_SHLIB
suffix = $$QMAKE_EXTENSION_SHLIB
}
MODULE_PRI_CONT = \
"QMAKE_INCDIR_$${ucmodule} = $$val_escape(MODULE_INCLUDEPATH)" \
"QMAKE_DEFINES_$${ucmodule} = $$val_escape(MODULE_DEFINES)"
debug_and_release {
win32: MODULE_DEBUG_LIBS = -L$$DESTDIR -l$${TARGET}d
darwin: MODULE_DEBUG_LIBS = -L$$DESTDIR -l$${TARGET}_debug
MODULE_RELEASE_LIBS = -L$$DESTDIR -l$$TARGET
win32: \
MODULE_DEBUG_LIBS = $$DESTDIR/$$prefix$${TARGET}d.$$suffix
else: darwin: \
MODULE_DEBUG_LIBS = $$DESTDIR/$$prefix$${TARGET}_debug.$$suffix
else: \
error("'$$QMAKE_PLATFORM' does not do debug_and_release.")
MODULE_RELEASE_LIBS = $$DESTDIR/$$prefix$${TARGET}.$$suffix
MODULE_PRI_CONT += \
"QMAKE_LIBS_$${ucmodule} =" \ # Needed for the module to be recognized.
"QMAKE_LIBS_$${ucmodule}_DEBUG = $$val_escape(MODULE_DEBUG_LIBS)" \
"QMAKE_LIBS_$${ucmodule}_RELEASE = $$val_escape(MODULE_RELEASE_LIBS)"
} else {
MODULE_LIBS = -L$$DESTDIR -l$$THE_TARGET
MODULE_LIBS = $$DESTDIR/$$prefix$${THE_TARGET}.$$suffix
MODULE_PRI_CONT += \
"QMAKE_LIBS_$${ucmodule} = $$val_escape(MODULE_LIBS)"
}

View File

@ -32,7 +32,6 @@
]
},
"network": {
"export": "",
"sources": [
{ "type": "makeSpec", "spec": "NETWORK" }
]

View File

@ -1,10 +1,10 @@
# custom tests
defineTest(qtConfLibrary_openssl) {
libs = $$getenv("OPENSSL_LIBS")
eval(libs = $$getenv("OPENSSL_LIBS"))
!isEmpty(libs) {
eval($${1}.libs = $$libs)
export($${1}.libs)
!qtConfResolveLibs($${1}.libs, $$libs): \
return(false)
return(true)
}
qtLog("$OPENSSL_LIBS is not set.")

View File

@ -1,29 +1,16 @@
# custom tests
defineReplace(filterLibraryPath) {
str = $${1}
for (l, QMAKE_DEFAULT_LIBDIRS): \
str -= "-L$$l"
return($$str)
}
defineTest(qtConfLibrary_psqlConfig) {
pg_config = $$config.input.psql_config
isEmpty(pg_config): \
pg_config = $$qtConfFindInPath("pg_config")
!win32:!isEmpty(pg_config) {
qtRunLoggedCommand("$$pg_config --libdir", libdir)|return(false)
!qtConfResolvePathLibs($${1}.libs, $$libdir, -lpq): \
return(false)
qtRunLoggedCommand("$$pg_config --includedir", includedir)|return(false)
libdir -= $$QMAKE_DEFAULT_LIBDIRS
libs =
!isEmpty(libdir): libs += "-L$$libdir"
libs += "-lpq"
$${1}.libs = $$libs
includedir -= $$QMAKE_DEFAULT_INCDIRS
$${1}.includedir = $$includedir
export($${1}.libs)
export($${1}.includedir)
!qtConfResolvePathIncs($${1}.includedir, $$includedir): \
return(false)
return(true)
}
qtLog("pg_config not found.")
@ -34,8 +21,9 @@ defineTest(qtConfLibrary_psqlEnv) {
# Respect PSQL_LIBS if set
PSQL_LIBS = $$getenv(PSQL_LIBS)
!isEmpty(PSQL_LIBS) {
eval($${1}.libs = $$PSQL_LIBS)
export($${1}.libs)
eval(libs = $$PSQL_LIBS)
!qtConfResolveLibs($${1}.libs, $$libs): \
return(false)
} else {
!qtConfLibrary_inline($$1, $$2): \
return(false)
@ -58,7 +46,6 @@ defineTest(qtConfLibrary_mysqlConfig) {
qtRunLoggedCommand("$$mysql_config $$query", libs)|return(false)
qtRunLoggedCommand("$$mysql_config --include", includedir)|return(false)
eval(libs = $$libs)
libs = $$filterLibraryPath($$libs)
# -rdynamic should not be returned by mysql_config, but is on RHEL 6.6
libs -= -rdynamic
equals($${1}.cleanlibs, true) {
@ -69,16 +56,15 @@ defineTest(qtConfLibrary_mysqlConfig) {
}
libs = $$cleanlibs
}
$${1}.libs = $$libs
!qtConfResolveLibs($${1}.libs, $$libs): \
return(false)
eval(rawincludedir = $$includedir)
rawincludedir ~= s/^-I//g
includedir =
for (id, rawincludedir): \
includedir += $$clean_path($$id)
includedir -= $$QMAKE_DEFAULT_INCDIRS
$${1}.includedir = $$includedir
export($${1}.libs)
export($${1}.includedir)
!qtConfResolvePathIncs($${1}.includedir, $$includedir): \
return(false)
return(true)
}
qtLog("mysql_config not found.")
@ -86,14 +72,14 @@ defineTest(qtConfLibrary_mysqlConfig) {
}
defineTest(qtConfLibrary_sybaseEnv) {
libs =
libdir =
sybase = $$getenv(SYBASE)
!isEmpty(sybase): \
libs += "-L$${sybase}/lib"
eval(libs += $$getenv(SYBASE_LIBS))
!isEmpty(libs) {
$${1}.libs = $$libs
export($${1}.libs)
}
libdir += $${sybase}/lib
eval(libs = $$getenv(SYBASE_LIBS))
isEmpty(libs): \
libs = $$eval($${1}.libs)
!qtConfResolvePathLibs($${1}.libs, $$libdir, $$libs): \
return(false)
return(true)
}