XCode 中的动态库

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1832316/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-14 18:59:02  来源:igfitidea点击:

dynamic libraries in XCode

cocoaxcodedylib

提问by Chris Becke

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

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

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.

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

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.

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

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.

我更希望我的应用程序在它的应用程序包中的某个地方寻找它的 dynlib(并且某些文档似乎确认这是正确的方法),但我不知道如何。

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?

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



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 :(

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

So, my questions (not answered in the other thread) now are: 1. How do I enter a meaningful relativepath 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?

所以,我的问题(未在其他线程中回答)现在是: 1. 如何在 Target Info -> ... -> Installation Directory 设置中输入有意义的相对路径,以及 2. 如何让 XCode 自动运行将 dylib 'target' 复制到应用程序包目标的相对位置的包文件夹中?

回答by Chris Becke

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

最后。找到了一些官方文档。完全可以在 XCode 中做到这一点。

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

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

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

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

Simple. Automatic.

简单的。自动的。

回答by Brock Woolf

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 otoolcommand to modify the binary after it is compiled (using a build script).

应用程序正在文件系统中寻找一个点,但它只是在应用程序包中找不到它之后才这样做。您需要otool在编译后使用该命令来修改二进制文件(使用构建脚本)。

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

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

Good luck.

祝你好运。

回答by acecilia

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.

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

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:

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

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.

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

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

2- 第二行:您正在检查的 dylib 的安装名称。(macports 将它们安装在 /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)

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

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

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

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:

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

@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.

2- 将我们需要的所有 dylib 复制到 xCode,但不是 /opt/local/lib 文件夹中的所有 dylib,只是我们需要的:(所有这些都太多了,也许 500Mb)我们需要遵循来自我们知道我们需要的 dylib(通常是 4 或 5 个)和包含的 dylib 的链接,因为这 4 或 5 个需要它们才能工作。

Y finally did it this way:

Y终于这样做了:

a) To change the paths:

a) 要更改路径:

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

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

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

2- 删除 lib 文件夹中所有不是 .dylib 存档的文件。

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

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

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

(在 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- Execute it:

4-执行它:

cd Desktop/lib
sudo ./theNameYouPrefer.sh

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

作为 sudo 运行它真的很重要,因为 dylib 可能被写保护。

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

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

otool -L theDylibYouPrefer.dylib

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

b) 只选择需要的 dylib,而不是所有的 lib 文件夹:

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

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

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

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

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

3- 将您知道肯定需要它们的重要 dylib 复制到 exampleFolder 内,在我的情况下它们是: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:

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- Execute this script a lot of times, until you appreciate that the number of files inside exampleFolder does not change.

5- 多次执行此脚本,直到您意识到 exampleFolder 中的文件数量不会改变。

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)

6- 您需要的 dylib 都在 exampleFolder 中!就我而言,我有 61 个 dylib。(记得我们开始的时候我放了 4 个 dylib)

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.

7- 您需要做的最后一件事是将 xCode 中的“Frameworks”文件夹放在里面。之后记得转到“构建阶段”并添加“复制文件”阶段:“编辑器”=>“添加构建阶段”=>“添加复制文件构建阶段”并在“复制文件”阶段中单击加号图标并添加您在“Framewroks”文件夹中找到的所有 DYLIBS。您需要的目标是框架。

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

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