Xcode does not rebuild app when source file updated in dependent static library

  • I have encountered an issue with Xcode's implicit dependency checking
    and static libraries, which I believe to be a bug in Xcode (and have
    reported as such); I'm raising it here in case anyone else has any
    ideas about it.  In brief, if an application depends on a static
    library, and a source file that is a component of the library is
    modified, Xcode rebuilds the library but does not relink the
    application, so the change is not seen in the application.

    More specifically: I have a workspace that contains an application
    project and a static library project, such that the application calls
    a function in the library (and the result is visible in the
    application: e.g. the function returns text that is displayed in a
    label in the application).  The static library is included in the
    "Link Binary with Libraries" build phase of the application target.
    Building from scratch causes the library to be built first, then the
    application, as expected (in other words, Xcode has detected the
    dependency).

    Now, if I modify the text of the message in the library source file,
    then click the "build and run" button, Xcode correctly rebuilds the
    library, but *fails* to relink the application, so when the
    application runs, the unmodified message text is displayed.

    I am running Xcode 4.5.1 under Mac OS X 10.8.2.  In the scenario I
    reported, the application is an iOS single-view application and the
    static library function being called happens to be implemented in C++.
    (This matches the scenario I encountered at my current position.)

    I have reported the issue as <rdar://12535282>.  Currently I know of
    no workaround other than cleaning and rebuilding.

    Has anyone else seen this, or has any other insight?  Thanks in advance.

    -- Russell Finn
  • On Oct 19, 2012, at 8:54 AM, Russell Finn <rsfinn...> wrote:

    > Now, if I modify the text of the message in the library source file,
    > then click the "build and run" button, Xcode correctly rebuilds the
    > library, but *fails* to relink the application, so when the
    > application runs, the unmodified message text is displayed.

    I have projects with these kinds of dependencies, and have not seen this problem.
    It sounds like Xcode doesn’t realize that the static library it’s linking into the app is the product of the library target.
    How did you add the library to the application’s build? In my experience the most reliable way is to add it using the “+” button in the Link Binary With Libraries build phase list, and then choosing the library from the list of the project’s products.

    —Jens
  • On Fri, Oct 19, 2012 at 12:13 PM, Jens Alfke <jens...> wrote:
    > How did you add the library to the application’s build? In my experience the
    > most reliable way is to add it using the “+” button in the Link Binary With
    > Libraries build phase list, and then choosing the library from the list of
    > the project’s products.

    Yes, that's exactly what I did.  Very puzzling.

    -- Russell
  • At my office-mate's suggestion, I checked out Stack Overflow, and when
    I couldn't find anything on first search, I tried writing up my
    question to post there.  Turns out when you do this, SO offers you a
    pretty good list of related questions, and in one of them I found a
    good potential workaround.

    When you add the static library to your application target (as Jens
    suggested, by using the Add button in the Link Binary With Libraries
    build phase), the library is added to your project with its location
    set Relative to Group (in the File Inspector).  Changing this setting
    to Relative to Build Products was sufficient to solve the problem in
    my test case: an immediate Build and Run caused Xcode to correctly
    relink my application (picking up the last change I'd made to the
    library).  I'm now off to apply this solution to my actual project's
    workspace, which contains a half-dozen or more static libraries and
    two separate applications.

    In my opinion this is still a bug in Xcode, but it's much more
    tractable with this workaround.  (I'll update my radar shortly.)

    -- Russell

    P.S. Credit where credit's due: the original source of this workaround
    is in the Apple Developer Forums at
    <https://devforums.apple.com/message/419328#419328>. For those without
    access to the forums, it is referenced in Stack Overflow at
    <http://stackoverflow.com/a/11826682/34498>.
  • On Oct 19, 2012, at 9:13 AM, Jens Alfke <jens...> wrote:
    > On Oct 19, 2012, at 8:54 AM, Russell Finn <rsfinn...> wrote:
    >> Now, if I modify the text of the message in the library source file,
    >> then click the "build and run" button, Xcode correctly rebuilds the
    >> library, but *fails* to relink the application, so when the
    >> application runs, the unmodified message text is displayed.
    >
    > I have projects with these kinds of dependencies, and have not seen this problem.
    > It sounds like Xcode doesn’t realize that the static library it’s linking into the app is the product of the library target.

    It's heartening (if a bit baffling to me) that not everyone using static libraries is hitting this, but yes, this is a known bug in Xcode.

    The bug isn't specifically due to static libraries (you can probably contrive a situation where it would happen for dynamic libraries), but it is more serious for more static libraries since of course it's critical that static libraries get relinked because that's how your changes make it into your app.  For dynamic libraries (which aren't available for iOS developers, but are for OS X developers), a large set of possible changes (though obviously not all of them) don't need to be detected at the time the app is relinked because they won't actually result in a changed app binary; instead the changes get picked up dynamically at run time when the dylib is loaded.

    The best workaround would be to add a shell script build phase to your app target to check whether the static library's modification date is newer than that for the app's binary, and if so to remove the app's binary to force it to be relinked.

    --
    Michael Rawdon
    <rawdon...>
    Xcode Developer
    Apple Inc., Cupertino CA
  • On Fri, Oct 19, 2012 at 10:40 PM, Michael Rawdon <rawdon...> wrote:
    > On Oct 19, 2012, at 9:13 AM, Jens Alfke <jens...> wrote:
    >
    > On Oct 19, 2012, at 8:54 AM, Russell Finn <rsfinn...> wrote:
    >
    > Now, if I modify the text of the message in the library source file,
    > then click the "build and run" button, Xcode correctly rebuilds the
    > library, but *fails* to relink the application, so when the
    > application runs, the unmodified message text is displayed.
    >
    >
    > I have projects with these kinds of dependencies, and have not seen this
    > problem.
    > It sounds like Xcode doesn’t realize that the static library it’s linking
    > into the app is the product of the library target.
    >
    >
    > It's heartening (if a bit baffling to me) that not everyone using static
    > libraries is hitting this, but yes, this is a known bug in Xcode.
    >
    > The bug isn't specifically due to static libraries (you can probably
    > contrive a situation where it would happen for dynamic libraries), but it is
    > more serious for more static libraries since of course it's critical that
    > static libraries get relinked because that's how your changes make it into
    > your app.  For dynamic libraries (which aren't available for iOS developers,
    > but are for OS X developers), a large set of possible changes (though
    > obviously not all of them) don't need to be detected at the time the app is
    > relinked because they won't actually result in a changed app binary; instead
    > the changes get picked up dynamically at run time when the dylib is loaded.
    >
    > The best workaround would be to add a shell script build phase to your app
    > target to check whether the static library's modification date is newer than
    > that for the app's binary, and if so to remove the app's binary to force it
    > to be relinked.

    Another 'workaround' I found to be working is to explicitly set the location
    of static library to "Relative to Build Products".
    Once the Location is changed, Xcode tries to figure out a new path and
    end up with some relative path like
    "../../../Library/Developer/Xcode/DerivedData/.…/libNAME.a".
    Manually editing the pbxproject and changing the path to "libNAME.a"
    (as it's relative to Build Products)
    seems to fix the issue of Xcode not relinking the binary.
    A nice side effect is that the static libraries don't show up in red
    in the navigator anymore.

    HTH,
    Stephan
previous month october 2012 next month
MTWTFSS
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31        
Go to today