XCode 中的动态库

发布于 2024-08-13 14:41:16 字数 787 浏览 4 评论 0原文

我正在尝试在 XCode 中创建一个 mac 应用程序,该应用程序的一些实现在动态库中。

我向我的 XCode cocoa 项目添加了一个新目标(动态库),在与框架和预编译头进行了一些斗争之后,进行了 dynlib 编译 - 并从调试器成功运行。

然而,当独立运行时,很明显 dynlib 位于错误的位置。 “未加载库:/usr/local/lib/testlib.dynlib”。在 Windows(我更常用的平台)上,Dll 可以放置在与 exe 相同的文件夹中,以及系统路径上的任何位置。

我宁愿我的应用程序在其应用程序包中的某个位置查找其 dynlib (某些文档似乎确认这是正确的方法),但我不知道如何。

是否可以在 XCode 中配置项目,以便 dylib 实际上被复制到应用程序包中,应用程序将在其中查找它?


看来我不需要使用 otool 来重置搜索路径。如果我编辑目标信息 ->构建->部署->安装目录 我可以从 XCode 内部更改 dyld 将要查找 dylib 的路径。默认情况下,对于新的动态库项目,路径设置为 /usr/local/lib。我已将其更改为 ./ - otool 确认 ./ 现在是 dyld 将查找此特定动态模块的位置。不幸的是 ./ 似乎实际上并没有引用我的应用程序包中的任何目录:(

所以,我的问题(在其他线程中没有得到回答)现在是: 1. 如何在目标信息 -> 中输入有意义的相对路径...->安装目录设置,以及 2.如何让XCode自动将dylib“目标”复制到应用程序包目标的相对位置的包文件夹中?

I am trying to create an mac application in XCode that has some of its implementation in a dynamic library.

I added a new target (dynamic library) to my XCode cocoa project and after a bit of fighting with frameworks and precompiled headers, have the dynlib compiling - and running successfully from the debugger.

When run standalone however its apparent that the dynlib is in the wrong place. "Library not loaded: /usr/local/lib/testlib.dynlib". On Windows - my more usual platform - Dlls can be placed in the same folder as the exe, and anywhere on the system path.

I would rather like my application to look for its dynlib somewhere in its application bundle (and certain documents seem to confirm this as the correct approach), but I don't know how.

Is it possible to configure the project in XCode so that the dylib actually is copied into the app bundle, in a place where the app will look for it?


It seems I don't need to use otool to reset the search path. If I edit the Target Info -> Build -> Deployment -> Installation Directory I can change, from inside XCode, the path that dyld is going to look at for the dylib. By default for a new dynamic library project, the path was set to /usr/local/lib. Which I have changed to ./ - otool confirms that ./ is now where dyld is going to be looking for this specific dynamic module. Unfortunately ./ doesn't seem to actually refer to any directory in my application bundle :(

So, my questions (not answered in the other thread) now are:
1. How do I enter a meaningful relative path in the Target Info -> ... -> Installation Directory setting, and
2. How can I get XCode to automatically copy the dylib 'target' into the application bundle target's bundle folder at the relative location?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

奶茶白久 2024-08-20 14:41:16

终于。找到了一些官方文档。完全可以在 XCode 中完成此操作。

我正在修改库的安装目录设置:它需要是:
@executable_path/../Frameworks

然后我需要向库添加“复制文件”构建步骤,以将其实际复制到 Frameworks 文件夹。

简单的。自动的。

At last. Found some official documentation. Its possible to do this entirely within XCode.

I was halfway there modifying the Installed Directory setting of the library: It needed to be:
@executable_path/../Frameworks

Then I needed to add a "Copy Files" build step to the library to actually copy it to the Frameworks folder.

Simple. Automatic.

原谅过去的我 2024-08-20 14:41:16

我相信您没有在编译时将动态库复制到应用程序包中。

应用程序正在文件系统中寻找一个点,但只有在应用程序包中找不到它后才会执行此操作。编译后(使用构建脚本),您需要使用 otool 命令来修改二进制文件。

您会在之前提出的问题中找到答案:
如何在 Xcode 中创建动态库

祝你好运。

I believe you are not copying the dynamic library into the application bundle at compile time.

The application is looking for a point in the filesystem, but it only does this after not finding it inside the application bundle. You need to use the otool command to modify the binary after it is compiled (using a build script).

You will find you answer in this previously asked question:
How Do I Create a Dynamic Library in Xcode.

Good luck.

萌无敌 2024-08-20 14:41:16

经过大量研究后,我得到了它,我尝试将一些 openCV dylib 与我的应用程序打包,因为我收到“库未加载:....”错误。

Dylibs 有一个安装名称,指示您第一次安装它们时的安装位置(macports 将它们安装在 /opt/local/lib/ 上)。
他们还有通往其他需要工作的 dylib 的路径。例如,如果您有名为“libopencv_core.2.4.8.dylib”的 dylib,您可以通过此命令检查安装名称及其使用的其他 dylib 的路径:

otool -L libopencv_core.2.4.8.dylib

该命令的输出为:

libopencv_core.2.4.8.dylib:
/opt/local/lib/libopencv_core.2.4.dylib (compatibility version 2.4.0, current version 2.4.8)
/opt/local/lib/libz.1.dylib (compatibility version 1.0.0, current version 1.2.8)
/usr/lib/libc++.1.dylib (compatibility version 1.0.0, current version 120.0.0)
/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1197.1.1)

1- 第一行:名称您正在检查的文件的名称。

2-第二行:您正在检查的 dylib 的安装名称。 (macports 将它们安装在 /opt/local/lib/ 中)

3- 第三行:它需要工作但并非在所有 OSX 系统中的其他 dylib 的路径。 (macports 将它们安装在 /opt/local/lib/ 中,并且您拥有它们,因为您之前安装过,这就是为什么如果您将应用程序分发到其他 Mac,您会收到“未找到库”错误)

4 & 5 - 第 4 行和第 5 行:所有 macOSX 系统内的 dylib。您不需要将它们复制到您的项目中。

现在我们知道了这一点,我们的目标是:

1-更改 dylib 内的所有路径(安装所需的其他 dylib 的名称和路径),因为我们要将 dylib 放入应用程序的“Frameworks”目录中,当我们移动应用程序或将其复制到其他Mac,我们希望dylibs在应用程序目录内的“frameworks”文件夹中相互查找:我们将使用的路径是:(

@executable_path/../Frameworks/nameOFTheDylib.dylib

注意这两点非常重要!)

2-复制对我们需要的所有 dylib 进行 xCode,但不是 /opt/local/lib 文件夹中的所有 dylib,只是我们需要的:(所有这些都太多了,也许 500Mb)我们需要点击以下链接我们知道我们需要的 dylib(通常是 4 或 5 个)以及包含的 dylib,因为这 4 或 5 个需要它们才能工作。

Y 最终这样做了:

a) 更改路径:

1- 将所有 /opt/local/lib 文件复制到桌面。

2-删除 lib 文件夹内所有非 .dylib 存档的文件。

3-将此脚本放入我们刚刚在桌面上复制的 lib 文件夹(与 dylib 一起):(

在 textEdit 中复制此文本并将其另存为 theNameYouPrefer.sh)

#!/bin/bash
echo empieza el script

EXECFILE=${BUILT_PRODUCTS_DIR}/${EXECUTABLE_PATH}
OLDLIBPATH="/opt/local/lib/"
NEWLIBPATH="@executable_path/../Frameworks/"
ACTUALPATH=`pwd`
# space separated list of libraries
for TARGET in ${ACTUALPATH}/* ; do
TARGET=$(basename $TARGET)
    if [ ${TARGET: -6} == ".dylib" ]
    then
        echo otool -DX ${TARGET}
        TARGETID=`otool -DX ${TARGET}`
        echo ${TARGETID}

        echo install_name_tool -id ${NEWLIBPATH}${TARGET} ${TARGET}
        echo `install_name_tool -id ${NEWLIBPATH}${TARGET} ${TARGET}`

        for DYLIB in ${ACTUALPATH}/* ; do
        DYLIB=$(basename $DYLIB)
            if [ ${DYLIB: -6} == ".dylib" ]
            then
                echo install_name_tool -change ${TARGETID} ${NEWLIBPATH}${TARGET} ${DYLIB}
                echo `install_name_tool -change ${TARGETID} ${NEWLIBPATH}${TARGET} ${DYLIB}`
            else
                if [ ${DYLIB: -3} == ".sh" ]
                then
                    echo soyYo
                else
                    echo mkdir ${ACTUALPATH}/eliminadas/
                    echo `mkdir ${ACTUALPATH}/eliminadas/`
                    echo mv ${DYLIB} ${ACTUALPATH}/eliminadas
                    echo `mv ${TARGET} ${ACTUALPATH}/eliminadas`
                fi
            fi
        done
    else
if [ ${TARGET: -3} == ".sh" ] || ![ -h ${TARGET} ]
        then
            echo noMeElimino
        else
            echo mkdir ${ACTUALPATH}/eliminadas/
            echo `mkdir ${ACTUALPATH}/../eliminadas/`
            echo mv ${TARGET} ${ACTUALPATH}/eliminadas/${TARGET}
            echo `mv ${TARGET} ${ACTUALPATH}/../eliminadas`
        fi
    fi
done

echo finaliza el script

4- 执行它:

cd Desktop/lib
sudo ./theNameYouPrefer.sh

运行它非常重要sudo,因为 dylib 可能被写保护。

此时,您应该更改所有 dylibs 路径。您可以使用以下命令在某些 dylib 中检查它:

otool -L theDylibYouPrefer.dylib

b) 仅选择所需的 dylib,而不是全部 lib 文件夹:

1-将 lib 文件夹重命名为 lib2:lib =====> lib2

2- 在桌面上的 lib2 文件夹旁边创建另一个文件夹(使用您喜欢的名称,例如 exampleFolder)。

3-在 exampleFolder 中复制您肯定需要的重要 dylib,在我的例子中它们是:libopencv_core.2.4.8.dylib、libopencv_highgui.2.4.8.dylib、libopencv_imgproc.2.4.8.dylib、libopencv_objdetect。 2.4.8.dylib

4- 脚本:将其复制到 exampleFolder 中,重要的 dylib 旁边。我对脚本了解不多,所以这个有点脏:

#!/bin/bash
echo empieza el script

EXECFILE=${BUILT_PRODUCTS_DIR}/${EXECUTABLE_PATH}
OLDLIBPATH="/opt/local/lib/"
NEWLIBPATH="@executable_path/../Frameworks/"
ACTUALPATH=`pwd`
# space separated list of libraries
for TARGET in ${ACTUALPATH}/* ; do
TARGET=$(basename $TARGET)
    if [ ${TARGET: -6} == ".dylib" ]
    then
        echo otool -DX ${TARGET}
        TARGETID=`otool -L ${TARGET}`
echo ${TARGETID}

echo :::::::::::::::::::::::::::

ELIM=`echo ${TARGETID} | sed 's/([^)]*)/UUU/g'`
echo $ELIM
#echo ${TARGETID} | sed 's/([^)]*)/UUU/g'
ELIM=`echo $(awk '{gsub("@executable_path/../Frameworks/", "");print}' <<< ${ELIM})`
echo $ELIM

ELIM=`echo $(awk '{gsub(" UUU", "");print}' <<< ${ELIM})`
echo $ELIM

ELIM=`echo $(awk '{gsub(":", "");print}' <<< ${ELIM})`
echo $ELIM

IFS=' ' read -a ARRAY <<< $ELIM

for element in ${ARRAY[@]}
do
    echo $element
    if [[ ${element} == */* ]]
    then
        echo "NO FRAMEWORK";
    else
        echo `mkdir ${ACTUALPATH}/../copy`
        echo `cp ${ACTUALPATH}/../lib2/${element} ${ACTUALPATH}/${element}`
    fi
done


    else
if [ ${TARGET: -3} == ".sh" ] || ![ -h ${TARGET} ]
        then
            echo noMeElimino
        else
            echo mkdir ${ACTUALPATH}/eliminadas/
            echo `mkdir ${ACTUALPATH}/../eliminadas/`
            echo mv ${TARGET} ${ACTUALPATH}/eliminadas/${TARGET}
            echo `mv ${TARGET} ${ACTUALPATH}/../eliminadas`
        fi
    fi
done

echo finaliza el script

5- 多次执行这个脚本,直到您意识到 exampleFolder 内的文件数量没有改变。

6-您需要的 dylib 都在 exampleFolder 中!就我而言,我得到了 61 个 dylib。 (记住,当我们开始时,我在那里放置了 4 个 dylib)

7-您需要做的最后一件事是将其放入 xCode 中的“Frameworks”文件夹中。之后,请记住转到“构建阶段”并添加“复制文件”阶段:“编辑器”=>“添加构建阶段”=> “添加复制文件构建阶段”并在“复制文件”阶段内单击加号图标并添加您在“Framewroks”文件夹中找到的所有动态库。您需要的目的地是框架。

就是这样,我或多或少是这样理解的。

After a lot of research I got it, I was trying to package some openCV dylib's with my application because I was receiving the "Library not loaded:...." error.

Dylibs have an install name that indicates where you installed them when you did it the first time (macports installs them on /opt/local/lib/).
They also have the path to other dylib's that they need to work. For example, if you have the dylib called "libopencv_core.2.4.8.dylib" you can check the install name and the paths to other dylibs that it uses with this command:

otool -L libopencv_core.2.4.8.dylib

The output of the command is:

libopencv_core.2.4.8.dylib:
/opt/local/lib/libopencv_core.2.4.dylib (compatibility version 2.4.0, current version 2.4.8)
/opt/local/lib/libz.1.dylib (compatibility version 1.0.0, current version 1.2.8)
/usr/lib/libc++.1.dylib (compatibility version 1.0.0, current version 120.0.0)
/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1197.1.1)

1- First line: name of the file you are checking.

2- Second line: Install name of the dylib you are checking. (macports installs them in /opt/local/lib/)

3- Third line: Path to other dylibs that it needs to work that are not in all OSX systems. (macports installs them in /opt/local/lib/ and you have them because you previously installed, thats why if you distribute your app to other macs you get the "library not found" error)

4 & 5 - Lines 4 and 5: dylibs inside all macOSX systems. you don't need to copy them in your project.

Now we know this, our goals are:

1- Change all the paths inside dylibs (install names and paths to other dylibs that are needed) because we are going to put our dylibs inside the app in the "Frameworks" directory, and when we move the app or copy it to other mac we want the dylibs to look for each other inside "frameworks" folder inside the directory of our app: the path we will use is:

@executable_path/../Frameworks/nameOFTheDylib.dylib

(NOTE THE TWO POINTS ARE REALLY IMPORTANT!)

2- Copy to xCode all the dylibs that we need, but not all the dylibs inside the /opt/local/lib folder, JUST THE ONES WE NEED:(all of them are too much, maybe 500Mb) we will need to follow the links from the dylibs we know we need (usually 4 or 5) and the dylibs that are included because those 4 or 5 need them for working.

Y finally did it this way:

a) To change the paths:

1- Copy all the /opt/local/lib file to the desktop.

2- Remove all files inside the lib folder that are NOT .dylib archives.

3-Put this script inside the lib folder (together with the dylibs) we have just copied in the desktop:

(Copy this text in textEdit and save it as theNameYouPrefer.sh)

#!/bin/bash
echo empieza el script

EXECFILE=${BUILT_PRODUCTS_DIR}/${EXECUTABLE_PATH}
OLDLIBPATH="/opt/local/lib/"
NEWLIBPATH="@executable_path/../Frameworks/"
ACTUALPATH=`pwd`
# space separated list of libraries
for TARGET in ${ACTUALPATH}/* ; do
TARGET=$(basename $TARGET)
    if [ ${TARGET: -6} == ".dylib" ]
    then
        echo otool -DX ${TARGET}
        TARGETID=`otool -DX ${TARGET}`
        echo ${TARGETID}

        echo install_name_tool -id ${NEWLIBPATH}${TARGET} ${TARGET}
        echo `install_name_tool -id ${NEWLIBPATH}${TARGET} ${TARGET}`

        for DYLIB in ${ACTUALPATH}/* ; do
        DYLIB=$(basename $DYLIB)
            if [ ${DYLIB: -6} == ".dylib" ]
            then
                echo install_name_tool -change ${TARGETID} ${NEWLIBPATH}${TARGET} ${DYLIB}
                echo `install_name_tool -change ${TARGETID} ${NEWLIBPATH}${TARGET} ${DYLIB}`
            else
                if [ ${DYLIB: -3} == ".sh" ]
                then
                    echo soyYo
                else
                    echo mkdir ${ACTUALPATH}/eliminadas/
                    echo `mkdir ${ACTUALPATH}/eliminadas/`
                    echo mv ${DYLIB} ${ACTUALPATH}/eliminadas
                    echo `mv ${TARGET} ${ACTUALPATH}/eliminadas`
                fi
            fi
        done
    else
if [ ${TARGET: -3} == ".sh" ] || ![ -h ${TARGET} ]
        then
            echo noMeElimino
        else
            echo mkdir ${ACTUALPATH}/eliminadas/
            echo `mkdir ${ACTUALPATH}/../eliminadas/`
            echo mv ${TARGET} ${ACTUALPATH}/eliminadas/${TARGET}
            echo `mv ${TARGET} ${ACTUALPATH}/../eliminadas`
        fi
    fi
done

echo finaliza el script

4- Execute it:

cd Desktop/lib
sudo ./theNameYouPrefer.sh

It is REALLY IMPORTANT to run it as sudo, because the dylibs could be write-protected.

At this point you should have all the dylibs paths changed. You can check it in some dylibs with the command:

otool -L theDylibYouPrefer.dylib

b) Select just the dylibs needed, not all of the lib folder:

1-Rename the lib folder to lib2: lib =====> lib2

2- Create another folder (with the name you prefer, for example exampleFolder) in the desktop, NEXT TO lib2 folder.

3- Copy inside exampleFolder the important dylibs that you know you will need them for sure, in my case they are:libopencv_core.2.4.8.dylib, libopencv_highgui.2.4.8.dylib, libopencv_imgproc.2.4.8.dylib, libopencv_objdetect.2.4.8.dylib

4- Script: copy it inside exampleFolder, next to the important dylibs. I do not know much about scripts, so this one is a bit more dirty:

#!/bin/bash
echo empieza el script

EXECFILE=${BUILT_PRODUCTS_DIR}/${EXECUTABLE_PATH}
OLDLIBPATH="/opt/local/lib/"
NEWLIBPATH="@executable_path/../Frameworks/"
ACTUALPATH=`pwd`
# space separated list of libraries
for TARGET in ${ACTUALPATH}/* ; do
TARGET=$(basename $TARGET)
    if [ ${TARGET: -6} == ".dylib" ]
    then
        echo otool -DX ${TARGET}
        TARGETID=`otool -L ${TARGET}`
echo ${TARGETID}

echo :::::::::::::::::::::::::::

ELIM=`echo ${TARGETID} | sed 's/([^)]*)/UUU/g'`
echo $ELIM
#echo ${TARGETID} | sed 's/([^)]*)/UUU/g'
ELIM=`echo $(awk '{gsub("@executable_path/../Frameworks/", "");print}' <<< ${ELIM})`
echo $ELIM

ELIM=`echo $(awk '{gsub(" UUU", "");print}' <<< ${ELIM})`
echo $ELIM

ELIM=`echo $(awk '{gsub(":", "");print}' <<< ${ELIM})`
echo $ELIM

IFS=' ' read -a ARRAY <<< $ELIM

for element in ${ARRAY[@]}
do
    echo $element
    if [[ ${element} == */* ]]
    then
        echo "NO FRAMEWORK";
    else
        echo `mkdir ${ACTUALPATH}/../copy`
        echo `cp ${ACTUALPATH}/../lib2/${element} ${ACTUALPATH}/${element}`
    fi
done


    else
if [ ${TARGET: -3} == ".sh" ] || ![ -h ${TARGET} ]
        then
            echo noMeElimino
        else
            echo mkdir ${ACTUALPATH}/eliminadas/
            echo `mkdir ${ACTUALPATH}/../eliminadas/`
            echo mv ${TARGET} ${ACTUALPATH}/eliminadas/${TARGET}
            echo `mv ${TARGET} ${ACTUALPATH}/../eliminadas`
        fi
    fi
done

echo finaliza el script

5- Execute this script a lot of times, until you appreciate that the number of files inside exampleFolder does not change.

6- The dylibs you need are all of them inside exampleFolder! In my case, I got 61 dylibs. (remember when we started I placed there 4 dylibs)

7- The last thing you need to do is drop the inside the "Frameworks" folder in xCode. After that REMEMBER TO GO TO "BUILD PHASES" AND ADD A "copy files" PHASE: "editor"=>"add build phase" => "add copy files build phase" AND INSIDE THE "copy files" PHASE CLICK IN THE PLUS ICON AND ADD THERE ALL THE DYLIBS YOU FIND IN "Framewroks" FOLDER. The destination you need is Frameworks.

And thats it, I got it this way more or less.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文