Skip to content

Commit

Permalink
Detect relocatable Qt build
Browse files Browse the repository at this point in the history
  • Loading branch information
kevle committed Sep 16, 2024
1 parent 2844e28 commit 61a89d0
Showing 1 changed file with 60 additions and 28 deletions.
88 changes: 60 additions & 28 deletions src/appimagetool/appdirtool.go
Original file line number Diff line number Diff line change
Expand Up @@ -311,7 +311,6 @@ func AppDirDeploy(path string) {
handleNvidia()

for _, lib := range allELFs {

deployElf(lib, appdir, err)
patchRpathsInElf(appdir, libraryLocationsInAppDir, lib)

Expand Down Expand Up @@ -1257,22 +1256,16 @@ func handleQt(appdir helpers.AppDir, qtVersion int) {

if qtVersion >= 5 {

// Actually the libQt5Core.so.5/libQt6Core.so.6 contains (always?) qt_prfxpath=... which tells us the location in which 'plugins/' is located
// When libQt5Core.so.5/libQt6Core.so.6 is built non-relocatable, it contains qt_prfxpath=...
// This tells us the path in which 'plugins/' is located

library, err := findLibrary(fmt.Sprintf("libQt%dCore.so.%d", qtVersion, qtVersion))
if err != nil {
helpers.PrintError(fmt.Sprintf("Could not find libQt%dCore.so.%d", qtVersion, qtVersion), err)
os.Exit(1)
}

f, err := os.Open(library)
defer f.Close()
if err != nil {
helpers.PrintError(fmt.Sprintf("Could not open libQt%dCore.so.%d", qtVersion, qtVersion), err)
os.Exit(1)
}

qtPrfxpath := getQtPrfxpath(f, err, qtVersion)
qtPrfxpath := getQtPrfxpath(library, qtVersion)

if qtPrfxpath == "" {
log.Println("Got empty qtPrfxpath, exiting")
Expand Down Expand Up @@ -1320,8 +1313,8 @@ func handleQt(appdir helpers.AppDir, qtVersion int) {
}
}

// platform plugin context - required for special characters - included if libQt5Gui.so.5/libQt6.Gui.so.6 is included
// similar to https://github.com/probonopd/linuxdeployqt/blob/42e51ea7c7a572a0aa1a21fc47d0f80032809d9d/tools/linuxdeployqt/shared.cpp#L1229
// platform plugin context - required for special characters - included if libQt5Gui.so.5/libQt6.Gui.so.6 is included
// similar to https://github.com/probonopd/linuxdeployqt/blob/42e51ea7c7a572a0aa1a21fc47d0f80032809d9d/tools/linuxdeployqt/shared.cpp#L1229
for _, lib := range allELFs {
if strings.HasSuffix(lib, fmt.Sprintf("libQt%dGui.so.%d", qtVersion, qtVersion)) == true {
if helpers.Exists(qtPrfxpath + "/plugins/platforminputcontexts/") {
Expand Down Expand Up @@ -1495,7 +1488,27 @@ func handleQt(appdir helpers.AppDir, qtVersion int) {
}
}

func getQtPrfxpath(f *os.File, err error, qtVersion int) string {
func getQtPrfxpath(library string, qtVersion int) string {
// Some notes on Qt behavior:
// https://doc.qt.io/qt-5/qt-conf.html
// https://doc.qt.io/qt-6/qt-conf.html
// qt.conf can be used to override default hardcoded paths
// qt6.conf can be used when Qt6 and Qt5 are deployed side-by-side

// https://doc.qt.io/qt-5/qlibraryinfo.html
// https://doc.qt.io/qt-6/qlibraryinfo.html
// Query paths at runtime using QLibraryInfo::location ( Qt5 ) and QLibraryInfo::path ( Qt6 )

// Qt source files relevant to this:
// qtbase/cmake/QtBuildRepoHelpers.cmake -- Configures prerequisites for QT_BUILD_INTERNALS_RELOCATABLE_INSTALL_PREFIX
// qtbase/cmake/QtBuildInternalsExtra.cmake.in -- Configures QT_BUILD_INTERNALS_RELOCATABLE_INSTALL_PREFIX ( relative path to Qt%d directory for relocatable library )
// qtbase/cmake/QtQmakeHelpers.cmake -- has function qt_generate_qconfig_cpp
// qtbase/src/corelib/CMakeLists.txt -- Configures qconfig.cpp.in
// qtbase/src/corelib/global/qconfig.cpp.in -- string constant with qt_prfxpath=
// qtbase/src/corelib/global/qlibraryinfo.h -- Class that handles Qt paths
// qtbase/src/corelib/global/qlibraryinfo.cpp -- "

// TODO IDEA: Use AppRun to generate qt.conf at application start?

// If the user has set $QTDIR or $QT_ROOT_DIR, use that instead of the one from qt_prfxpath in the library
qtPrefixEnv := os.Getenv("QTDIR")
Expand All @@ -1507,6 +1520,13 @@ func getQtPrfxpath(f *os.File, err error, qtVersion int) string {
return qtPrefixEnv
}

f, err := os.Open(library)
if err != nil {
helpers.PrintError(fmt.Sprintf("Could not open libQt%dCore.so.%d", qtVersion, qtVersion), err)
os.Exit(1)
}
defer f.Close()

f.Seek(0, 0)
// Search from the beginning of the file
search := []byte("qt_prfxpath=")
Expand All @@ -1516,21 +1536,33 @@ func getQtPrfxpath(f *os.File, err error, qtVersion int) string {
// From the current location in the file, search to the next 0x00 byte
f.Seek(offset, 0)
length := ScanFile(f, search)
log.Println("Length of value of qt_prfxpath:", length)
// Now that we know where in the file the information is, go get it
f.Seek(offset, 0)
buf := make([]byte, length)
// Make a buffer that is exactly as long as the range we want to read
_, err = io.ReadFull(f, buf)
if err != nil {
helpers.PrintError("Unable to read qt_prfxpath", err)
os.Exit(1)
}
qt_prfxpath := strings.TrimSpace(string(buf))
log.Println("qt_prfxpath:", qt_prfxpath)
if qt_prfxpath == "" {
log.Println("Could not get qt_prfxpath")
return ""

var qt_prfxpath = ""

// When length is 0, Qt has been built as relocatable
if length == 0 {
// Directory should be in ../Qt${qtVersion}
// TODO: Check if this is true for relocatable binaries in Qt5
qt_prfxpath = filepath.Dir(library) + fmt.Sprintf("/../Qt%d", qtVersion)
log.Println("Using Qt prefix path:", qt_prfxpath)
} else {
log.Println("Length of value of qt_prfxpath:", length)

// Now that we know where in the file the information is, go get it
f.Seek(offset, 0)
buf := make([]byte, length)
// Make a buffer that is exactly as long as the range we want to read
_, err = io.ReadFull(f, buf)
if err != nil {
helpers.PrintError("Unable to read qt_prfxpath", err)
os.Exit(1)
}
qt_prfxpath = strings.TrimSpace(string(buf))
log.Println("qt_prfxpath:", qt_prfxpath)
if qt_prfxpath == "" {
log.Println("Could not get qt_prfxpath")
return ""
}
}

// Special case:
Expand Down

0 comments on commit 61a89d0

Please sign in to comment.