diff mbox

[PATCHv3,for,next,2/2] toolchain: create symlink to 'lib' from ARCH_LIB_DIR iso fixed lib32/lib64

Message ID 1424259375-20288-3-git-send-email-patrickdepinguin@gmail.com
State Changes Requested
Headers show

Commit Message

Thomas De Schampheleire Feb. 18, 2015, 11:36 a.m. UTC
From: Thomas De Schampheleire <thomas.de.schampheleire@gmail.com>

Currently, following symbolic links are created in both target and
staging directories:
- lib(32|64) --> lib
- usr/lib(32|64) --> lib

The decision for lib32 or lib64 is based on the target architecture
configuration in buildroot (BR2_ARCH_IS_64).

In at least one case this is not correct: when building for a Cavium Octeon
III processor using the toolchain from the Cavium Networks SDK, and
specifying -march=octeon3 in BR2_TARGET_OPTIMIZATION, libraries are expected
in directory 'lib32-fp' rather than 'lib32' (likewise for lib64-fp).

More generally, for external toolchains, the correct symbolic link is
from (usr/)${ARCH_LIB_DIR} to lib. For internal toolchains, current
toolchains always use either lib32 or lib64.

Fix the problem as follows:
- create symlink creation helpers in toolchain/helpers.mk
- for external toolchains, call these helpers based on ARCH_LIB_DIR
- for internal toolchains, call these helpers based on the existing
  fixed lib32/lib64 logic, moved from Makefile
- to fix build order problems, add the correct dependency on
  $(BUILD_DIR) from $(BUILD_DIR)/.root

Signed-off-by: Thomas De Schampheleire <thomas.de.schampheleire@gmail.com>

---
v3:
- update commit message wrapping
- change dependency on $(BUILD_DIR) to a order-only dependency
v2:
- fix 'lib32-fp' leftover in toolchain-buildroot
- silence commands creating symlink with $(Q)
- fix case where ARCH_LIB_DIR is 'lib'

Note: the handling in the internal toolchain is a bit awkward because it
explicitly adds a new target, but I don't see a much better way: it must
be done _before_ the toolchain is being built. The entire logic cannot
be done in Makefile as ARCH_LIB_DIR is not available there.
---
 Makefile                                             | 14 +-------------
 toolchain/helpers.mk                                 | 16 ++++++++++++++++
 toolchain/toolchain-buildroot/toolchain-buildroot.mk | 11 +++++++++++
 toolchain/toolchain-external/toolchain-external.mk   | 12 ++++++++++++
 4 files changed, 40 insertions(+), 13 deletions(-)

Comments

Arnout Vandecappelle July 13, 2015, 4:57 p.m. UTC | #1
Hi Thomas,

 Sorry that it is taking so long to make progress on this, but the external
toolchain stuff is, as you know, horribly demotivating... We've spent quite a
bit of time to understand what this patch does and how it could be done better...

On 02/18/15 12:36, Thomas De Schampheleire wrote:
> From: Thomas De Schampheleire <thomas.de.schampheleire@gmail.com>
> 
> Currently, following symbolic links are created in both target and
> staging directories:
> - lib(32|64) --> lib
> - usr/lib(32|64) --> lib
> 
> The decision for lib32 or lib64 is based on the target architecture
> configuration in buildroot (BR2_ARCH_IS_64).
> 
> In at least one case this is not correct: when building for a Cavium Octeon
> III processor using the toolchain from the Cavium Networks SDK, and
> specifying -march=octeon3 in BR2_TARGET_OPTIMIZATION, libraries are expected
> in directory 'lib32-fp' rather than 'lib32' (likewise for lib64-fp).
> 
> More generally, for external toolchains, the correct symbolic link is
> from (usr/)${ARCH_LIB_DIR} to lib. For internal toolchains, current
> toolchains always use either lib32 or lib64.
> 
> Fix the problem as follows:
> - create symlink creation helpers in toolchain/helpers.mk
> - for external toolchains, call these helpers based on ARCH_LIB_DIR
> - for internal toolchains, call these helpers based on the existing
>   fixed lib32/lib64 logic, moved from Makefile
> - to fix build order problems, add the correct dependency on
>   $(BUILD_DIR) from $(BUILD_DIR)/.root

 It's not clear to us which build order problems are solved by this, and
especially how these build order problems are introduced by this patch... Could
you explain that a little?

> 
> Signed-off-by: Thomas De Schampheleire <thomas.de.schampheleire@gmail.com>
> 
> ---
> v3:
> - update commit message wrapping
> - change dependency on $(BUILD_DIR) to a order-only dependency
> v2:
> - fix 'lib32-fp' leftover in toolchain-buildroot
> - silence commands creating symlink with $(Q)
> - fix case where ARCH_LIB_DIR is 'lib'
> 
> Note: the handling in the internal toolchain is a bit awkward because it
> explicitly adds a new target, but I don't see a much better way: it must
> be done _before_ the toolchain is being built. The entire logic cannot
> be done in Makefile as ARCH_LIB_DIR is not available there.
> ---
>  Makefile                                             | 14 +-------------
>  toolchain/helpers.mk                                 | 16 ++++++++++++++++
>  toolchain/toolchain-buildroot/toolchain-buildroot.mk | 11 +++++++++++
>  toolchain/toolchain-external/toolchain-external.mk   | 12 ++++++++++++
>  4 files changed, 40 insertions(+), 13 deletions(-)
> 
> diff --git a/Makefile b/Makefile
> index 338c992..de202b0 100644
> --- a/Makefile
> +++ b/Makefile
> @@ -449,20 +449,10 @@ world: target-post-image
>  $(BUILD_DIR) $(HOST_DIR) $(BINARIES_DIR) $(LEGAL_INFO_DIR) $(REDIST_SOURCES_DIR_TARGET) $(REDIST_SOURCES_DIR_HOST):
>  	@mkdir -p $@
>  
> -# We make a symlink lib32->lib or lib64->lib as appropriate
> -# MIPS64/n32 requires lib32 even though it's a 64-bit arch.
> -ifeq ($(BR2_ARCH_IS_64)$(BR2_MIPS_NABI32),y)
> -LIB_SYMLINK = lib64
> -else
> -LIB_SYMLINK = lib32
> -endif

 Yeah, it's good to see this disappear from top-level Makefile!

> -
>  $(STAGING_DIR):
>  	@mkdir -p $(STAGING_DIR)/bin
>  	@mkdir -p $(STAGING_DIR)/lib
> -	@ln -snf lib $(STAGING_DIR)/$(LIB_SYMLINK)
>  	@mkdir -p $(STAGING_DIR)/usr/lib
> -	@ln -snf lib $(STAGING_DIR)/usr/$(LIB_SYMLINK)
>  	@mkdir -p $(STAGING_DIR)/usr/include
>  	@mkdir -p $(STAGING_DIR)/usr/bin
>  	@ln -snf $(STAGING_DIR) $(BASE_DIR)/staging
> @@ -475,15 +465,13 @@ RSYNC_VCS_EXCLUSIONS = \
>  	--exclude .svn --exclude .git --exclude .hg --exclude .bzr \
>  	--exclude CVS
>  
> -$(BUILD_DIR)/.root:
> +$(BUILD_DIR)/.root: | $(BUILD_DIR)
>  	mkdir -p $(TARGET_DIR)
>  	rsync -a --ignore-times $(RSYNC_VCS_EXCLUSIONS) \
>  		--chmod=Du+w --exclude .empty --exclude '*~' \
>  		$(TARGET_SKELETON)/ $(TARGET_DIR)/
>  	$(INSTALL) -m 0644 support/misc/target-dir-warning.txt $(TARGET_DIR_WARNING_FILE)
> -	@ln -snf lib $(TARGET_DIR)/$(LIB_SYMLINK)
>  	@mkdir -p $(TARGET_DIR)/usr
> -	@ln -snf lib $(TARGET_DIR)/usr/$(LIB_SYMLINK)
>  	touch $@
>  
>  $(TARGET_DIR): $(BUILD_DIR)/.root
> diff --git a/toolchain/helpers.mk b/toolchain/helpers.mk
> index 3121da4..b4879e0 100644
> --- a/toolchain/helpers.mk
> +++ b/toolchain/helpers.mk
> @@ -1,5 +1,21 @@
>  # This Makefile fragment declares toolchain related helper functions.
>  
> +# Create the necessary symlink from (usr/)lib32|lib64|lib32-fp|... to lib
> +# In general, for external toolchains, the correct link name is $ARCH_LIB_DIR.
> +create_staging_lib_symlink = \
> +	LIB_SYMLINK="$(strip $1)" ; \
> +	if [ "$${LIB_SYMLINK}" != "lib" ]; then \
> +		ln -snf lib $(STAGING_DIR)/$${LIB_SYMLINK} ; \
> +		ln -snf lib $(STAGING_DIR)/usr/$${LIB_SYMLINK} ; \
> +	fi
> +
> +create_target_lib_symlink = \
> +	LIB_SYMLINK="$(strip $1)" ; \
> +	if [ "$${LIB_SYMLINK}" != "lib" ]; then \
> +	    ln -snf lib $(TARGET_DIR)/$${LIB_SYMLINK} ; \
> +	    ln -snf lib $(TARGET_DIR)/usr/$${LIB_SYMLINK} ; \
> +	fi

 These two functions are identical except for the target dir, so create just one
function with the directory as a second parameter.

> +
>  # The copy_toolchain_lib_root function copies a toolchain library and
>  # its symbolic links from the sysroot directory to the target
>  # directory. Note that this function is used both by the external
> diff --git a/toolchain/toolchain-buildroot/toolchain-buildroot.mk b/toolchain/toolchain-buildroot/toolchain-buildroot.mk
> index b30cc33..3ccb030 100644
> --- a/toolchain/toolchain-buildroot/toolchain-buildroot.mk
> +++ b/toolchain/toolchain-buildroot/toolchain-buildroot.mk
> @@ -12,6 +12,17 @@ BR_LIBC = $(call qstrip,$(BR2_TOOLCHAIN_BUILDROOT_LIBC))
>  
>  TOOLCHAIN_BUILDROOT_DEPENDENCIES = host-gcc-final
>  
> +ifeq ($(BR2_ARCH_IS_64)$(BR2_MIPS_NABI32),y)

 The comment about MIPS64/n32 should have been retained here.

> +LIB_SYMLINK = lib64
> +else
> +LIB_SYMLINK = lib32
> +endif

 Since now it is something specific to this .mk file, perhaps it should be
prefixed with TOOLCHAIN_BUILDROOT_

> +
> +host-gcc-final: create-lib-symlinks

 This is not just awkward, it also breaks top-level parallel build. At least, if
host-gcc-final really does need this to be done. In top-level parallel build,
the order between the dependencies is not set, so it's possible that the
symlinks are only created after the build of gcc has already started. Of course,
it's vanishingly unlikely that it will not yet have finished by the time the gcc
install step starts... Actually, we wonder if it is really needed before
gcc-final, or even before the libc? Because the way that make evaluates things
in the non-parallel case, this step would have been done before anything else,
even before host-binutils...

 If it really should be done before host-gcc-final, the full solution would be
to add this as a post-install hook to the libc. You could do something like this:

$(call uppercase,$(BR_LIBC))_POST_INSTALL_STAGING_HOOKS += \
	$(call create_staging_lib_symlink,$(LIB_SYMLINK))

Isn't that beautiful :-) This also has the advantage of splitting the staging
and target installs into their appropriate locations.

 Alternatively, you could add a tiny package without source that does this and
add that as a dependency to host-gcc-final.



 Do you still have the energy to make some changes and resubmit?

 Regards,
 Arnout

> +create-lib-symlinks: $(STAGING_DIR) $(TARGET_DIR)
> +	$(call create_staging_lib_symlink,$(LIB_SYMLINK))
> +	$(call create_target_lib_symlink,$(LIB_SYMLINK))
> +
>  TOOLCHAIN_BUILDROOT_ADD_TOOLCHAIN_DEPENDENCY = NO
>  
>  $(eval $(virtual-package))
> diff --git a/toolchain/toolchain-external/toolchain-external.mk b/toolchain/toolchain-external/toolchain-external.mk
> index e05957c..16e398c 100644
> --- a/toolchain/toolchain-external/toolchain-external.mk
> +++ b/toolchain/toolchain-external/toolchain-external.mk
> @@ -600,6 +600,16 @@ define TOOLCHAIN_EXTERNAL_INSTALL_SYSROOT_LIBS
>  	$(call copy_toolchain_sysroot,$${SYSROOT_DIR},$${ARCH_SYSROOT_DIR},$${ARCH_SUBDIR},$${ARCH_LIB_DIR},$${SUPPORT_LIB_DIR})
>  endef
>  
> +define TOOLCHAIN_EXTERNAL_CREATE_STAGING_LIB_SYMLINK
> +	$(Q)ARCH_LIB_DIR="$(call toolchain_find_libdir,$(TOOLCHAIN_EXTERNAL_CC) $(TOOLCHAIN_EXTERNAL_CFLAGS))" ; \
> +	$(call create_staging_lib_symlink,$${ARCH_LIB_DIR})
> +endef
> +
> +define TOOLCHAIN_EXTERNAL_CREATE_TARGET_LIB_SYMLINK
> +	$(Q)ARCH_LIB_DIR="$(call toolchain_find_libdir,$(TOOLCHAIN_EXTERNAL_CC) $(TOOLCHAIN_EXTERNAL_CFLAGS))" ; \
> +	$(call create_target_lib_symlink,$${ARCH_LIB_DIR})
> +endef
> +
>  # Special installation target used on the Blackfin architecture when
>  # FDPIC is not the primary binary format being used, but the user has
>  # nonetheless requested the installation of the FDPIC libraries to the
> @@ -699,6 +709,7 @@ define TOOLCHAIN_EXTERNAL_INSTALL_GDBINIT
>  endef
>  
>  define TOOLCHAIN_EXTERNAL_INSTALL_STAGING_CMDS
> +	$(TOOLCHAIN_EXTERNAL_CREATE_STAGING_LIB_SYMLINK)
>  	$(TOOLCHAIN_EXTERNAL_INSTALL_SYSROOT_LIBS)
>  	$(TOOLCHAIN_EXTERNAL_INSTALL_WRAPPER)
>  	$(TOOLCHAIN_EXTERNAL_INSTALL_GDBINIT)
> @@ -708,6 +719,7 @@ endef
>  # and the target directory, we do everything within the
>  # install-staging step, arbitrarily.
>  define TOOLCHAIN_EXTERNAL_INSTALL_TARGET_CMDS
> +	$(TOOLCHAIN_EXTERNAL_CREATE_TARGET_LIB_SYMLINK)
>  	$(TOOLCHAIN_EXTERNAL_INSTALL_TARGET_LIBS)
>  	$(TOOLCHAIN_EXTERNAL_INSTALL_BFIN_FDPIC)
>  	$(TOOLCHAIN_EXTERNAL_INSTALL_BFIN_FLAT)
>
Thomas De Schampheleire July 13, 2015, 8:19 p.m. UTC | #2
On Mon, Jul 13, 2015 at 6:57 PM, Arnout Vandecappelle <arnout@mind.be> wrote:
>  Hi Thomas,
>
>  Sorry that it is taking so long to make progress on this, but the external
> toolchain stuff is, as you know, horribly demotivating... We've spent quite a
> bit of time to understand what this patch does and how it could be done better...
>
> On 02/18/15 12:36, Thomas De Schampheleire wrote:
>> From: Thomas De Schampheleire <thomas.de.schampheleire@gmail.com>
>>
>> Currently, following symbolic links are created in both target and
>> staging directories:
>> - lib(32|64) --> lib
>> - usr/lib(32|64) --> lib
>>
>> The decision for lib32 or lib64 is based on the target architecture
>> configuration in buildroot (BR2_ARCH_IS_64).
>>
>> In at least one case this is not correct: when building for a Cavium Octeon
>> III processor using the toolchain from the Cavium Networks SDK, and
>> specifying -march=octeon3 in BR2_TARGET_OPTIMIZATION, libraries are expected
>> in directory 'lib32-fp' rather than 'lib32' (likewise for lib64-fp).
>>
>> More generally, for external toolchains, the correct symbolic link is
>> from (usr/)${ARCH_LIB_DIR} to lib. For internal toolchains, current
>> toolchains always use either lib32 or lib64.
>>
>> Fix the problem as follows:
>> - create symlink creation helpers in toolchain/helpers.mk
>> - for external toolchains, call these helpers based on ARCH_LIB_DIR
>> - for internal toolchains, call these helpers based on the existing
>>   fixed lib32/lib64 logic, moved from Makefile
>> - to fix build order problems, add the correct dependency on
>>   $(BUILD_DIR) from $(BUILD_DIR)/.root
>
>  It's not clear to us which build order problems are solved by this, and
> especially how these build order problems are introduced by this patch... Could
> you explain that a little?

As you may imagine, my memory of these issues is not so crisp anymore,
but IIRC without these build-order changes it would not build
correctly. I guess I was using 'make clean toolchain' and it would
fail, but I would need to retest explicitly to be sure.

>
>>
>> Signed-off-by: Thomas De Schampheleire <thomas.de.schampheleire@gmail.com>
>>
>> ---
>> v3:
>> - update commit message wrapping
>> - change dependency on $(BUILD_DIR) to a order-only dependency
>> v2:
>> - fix 'lib32-fp' leftover in toolchain-buildroot
>> - silence commands creating symlink with $(Q)
>> - fix case where ARCH_LIB_DIR is 'lib'
>>
>> Note: the handling in the internal toolchain is a bit awkward because it
>> explicitly adds a new target, but I don't see a much better way: it must
>> be done _before_ the toolchain is being built. The entire logic cannot
>> be done in Makefile as ARCH_LIB_DIR is not available there.
>> ---
>>  Makefile                                             | 14 +-------------
>>  toolchain/helpers.mk                                 | 16 ++++++++++++++++
>>  toolchain/toolchain-buildroot/toolchain-buildroot.mk | 11 +++++++++++
>>  toolchain/toolchain-external/toolchain-external.mk   | 12 ++++++++++++
>>  4 files changed, 40 insertions(+), 13 deletions(-)
>>
>> diff --git a/Makefile b/Makefile
>> index 338c992..de202b0 100644
>> --- a/Makefile
>> +++ b/Makefile
>> @@ -449,20 +449,10 @@ world: target-post-image
>>  $(BUILD_DIR) $(HOST_DIR) $(BINARIES_DIR) $(LEGAL_INFO_DIR) $(REDIST_SOURCES_DIR_TARGET) $(REDIST_SOURCES_DIR_HOST):
>>       @mkdir -p $@
>>
>> -# We make a symlink lib32->lib or lib64->lib as appropriate
>> -# MIPS64/n32 requires lib32 even though it's a 64-bit arch.
>> -ifeq ($(BR2_ARCH_IS_64)$(BR2_MIPS_NABI32),y)
>> -LIB_SYMLINK = lib64
>> -else
>> -LIB_SYMLINK = lib32
>> -endif
>
>  Yeah, it's good to see this disappear from top-level Makefile!
>
>> -
>>  $(STAGING_DIR):
>>       @mkdir -p $(STAGING_DIR)/bin
>>       @mkdir -p $(STAGING_DIR)/lib
>> -     @ln -snf lib $(STAGING_DIR)/$(LIB_SYMLINK)
>>       @mkdir -p $(STAGING_DIR)/usr/lib
>> -     @ln -snf lib $(STAGING_DIR)/usr/$(LIB_SYMLINK)
>>       @mkdir -p $(STAGING_DIR)/usr/include
>>       @mkdir -p $(STAGING_DIR)/usr/bin
>>       @ln -snf $(STAGING_DIR) $(BASE_DIR)/staging
>> @@ -475,15 +465,13 @@ RSYNC_VCS_EXCLUSIONS = \
>>       --exclude .svn --exclude .git --exclude .hg --exclude .bzr \
>>       --exclude CVS
>>
>> -$(BUILD_DIR)/.root:
>> +$(BUILD_DIR)/.root: | $(BUILD_DIR)
>>       mkdir -p $(TARGET_DIR)
>>       rsync -a --ignore-times $(RSYNC_VCS_EXCLUSIONS) \
>>               --chmod=Du+w --exclude .empty --exclude '*~' \
>>               $(TARGET_SKELETON)/ $(TARGET_DIR)/
>>       $(INSTALL) -m 0644 support/misc/target-dir-warning.txt $(TARGET_DIR_WARNING_FILE)
>> -     @ln -snf lib $(TARGET_DIR)/$(LIB_SYMLINK)
>>       @mkdir -p $(TARGET_DIR)/usr
>> -     @ln -snf lib $(TARGET_DIR)/usr/$(LIB_SYMLINK)
>>       touch $@
>>
>>  $(TARGET_DIR): $(BUILD_DIR)/.root
>> diff --git a/toolchain/helpers.mk b/toolchain/helpers.mk
>> index 3121da4..b4879e0 100644
>> --- a/toolchain/helpers.mk
>> +++ b/toolchain/helpers.mk
>> @@ -1,5 +1,21 @@
>>  # This Makefile fragment declares toolchain related helper functions.
>>
>> +# Create the necessary symlink from (usr/)lib32|lib64|lib32-fp|... to lib
>> +# In general, for external toolchains, the correct link name is $ARCH_LIB_DIR.
>> +create_staging_lib_symlink = \
>> +     LIB_SYMLINK="$(strip $1)" ; \
>> +     if [ "$${LIB_SYMLINK}" != "lib" ]; then \
>> +             ln -snf lib $(STAGING_DIR)/$${LIB_SYMLINK} ; \
>> +             ln -snf lib $(STAGING_DIR)/usr/$${LIB_SYMLINK} ; \
>> +     fi
>> +
>> +create_target_lib_symlink = \
>> +     LIB_SYMLINK="$(strip $1)" ; \
>> +     if [ "$${LIB_SYMLINK}" != "lib" ]; then \
>> +         ln -snf lib $(TARGET_DIR)/$${LIB_SYMLINK} ; \
>> +         ln -snf lib $(TARGET_DIR)/usr/$${LIB_SYMLINK} ; \
>> +     fi
>
>  These two functions are identical except for the target dir, so create just one
> function with the directory as a second parameter.

OK

>
>> +
>>  # The copy_toolchain_lib_root function copies a toolchain library and
>>  # its symbolic links from the sysroot directory to the target
>>  # directory. Note that this function is used both by the external
>> diff --git a/toolchain/toolchain-buildroot/toolchain-buildroot.mk b/toolchain/toolchain-buildroot/toolchain-buildroot.mk
>> index b30cc33..3ccb030 100644
>> --- a/toolchain/toolchain-buildroot/toolchain-buildroot.mk
>> +++ b/toolchain/toolchain-buildroot/toolchain-buildroot.mk
>> @@ -12,6 +12,17 @@ BR_LIBC = $(call qstrip,$(BR2_TOOLCHAIN_BUILDROOT_LIBC))
>>
>>  TOOLCHAIN_BUILDROOT_DEPENDENCIES = host-gcc-final
>>
>> +ifeq ($(BR2_ARCH_IS_64)$(BR2_MIPS_NABI32),y)
>
>  The comment about MIPS64/n32 should have been retained here.

True.

>
>> +LIB_SYMLINK = lib64
>> +else
>> +LIB_SYMLINK = lib32
>> +endif
>
>  Since now it is something specific to this .mk file, perhaps it should be
> prefixed with TOOLCHAIN_BUILDROOT_

OK.

>
>> +
>> +host-gcc-final: create-lib-symlinks
>
>  This is not just awkward, it also breaks top-level parallel build. At least, if
> host-gcc-final really does need this to be done. In top-level parallel build,
> the order between the dependencies is not set, so it's possible that the
> symlinks are only created after the build of gcc has already started.

Here I don't follow: the line above expresses that host-gcc-final
needs create-lib-symlinks. So even with top-level parallel build,
_first_ create-lib-symlinks is executed, and only then host-gcc-final.

Your statement seems to refer to cases like:

foo: bar baz

Where bar and baz can indeed be executed in parallel.
Or I'm misunderstanding you or the situation.


> Of course,
> it's vanishingly unlikely that it will not yet have finished by the time the gcc
> install step starts... Actually, we wonder if it is really needed before
> gcc-final, or even before the libc? Because the way that make evaluates things
> in the non-parallel case, this step would have been done before anything else,
> even before host-binutils...

For external toolchains the links are created after extraction, when
installing the toolchain in target and staging.
For internal toolchain I don't remember if it needs to be done before
host-gcc-final, or if it's enough that it is done after host-gcc-final
but I couldn't find a better way to achieve that because
host-gcc-final is the target used for toolchain/toolchain-buildroot,
so there wasn't a lot of hooking possibility without changing a lot of
code. I would need to retest to be sure.

>
>  If it really should be done before host-gcc-final, the full solution would be
> to add this as a post-install hook to the libc. You could do something like this:
>
> $(call uppercase,$(BR_LIBC))_POST_INSTALL_STAGING_HOOKS += \
>         $(call create_staging_lib_symlink,$(LIB_SYMLINK))
>
> Isn't that beautiful :-) This also has the advantage of splitting the staging
> and target installs into their appropriate locations.
>
>  Alternatively, you could add a tiny package without source that does this and
> add that as a dependency to host-gcc-final.
>
>
>
>  Do you still have the energy to make some changes and resubmit?

I'll see if I can look at some of this tomorrow but I can't make any
promises. But if you happen to be in the heat of the moment tonight
and can't resist reworking some of this then be my guest :-)
I'll log into IRC tomorrow...

Thanks for the feedback,
Thomas
Thomas De Schampheleire July 13, 2015, 8:25 p.m. UTC | #3
On July 13, 2015 10:19:58 PM CEST, Thomas De Schampheleire <patrickdepinguin@gmail.com> wrote:
>On Mon, Jul 13, 2015 at 6:57 PM, Arnout Vandecappelle <arnout@mind.be>
>wrote:
>>  Hi Thomas,
>>
>>  Sorry that it is taking so long to make progress on this, but the
>external
>> toolchain stuff is, as you know, horribly demotivating... We've spent
>quite a
>> bit of time to understand what this patch does and how it could be
>done better...
>>
>> On 02/18/15 12:36, Thomas De Schampheleire wrote:
>>> From: Thomas De Schampheleire <thomas.de.schampheleire@gmail.com>
>>>
>>> Currently, following symbolic links are created in both target and
>>> staging directories:
>>> - lib(32|64) --> lib
>>> - usr/lib(32|64) --> lib
>>>
>>> The decision for lib32 or lib64 is based on the target architecture
>>> configuration in buildroot (BR2_ARCH_IS_64).
>>>
>>> In at least one case this is not correct: when building for a Cavium
>Octeon
>>> III processor using the toolchain from the Cavium Networks SDK, and
>>> specifying -march=octeon3 in BR2_TARGET_OPTIMIZATION, libraries are
>expected
>>> in directory 'lib32-fp' rather than 'lib32' (likewise for lib64-fp).
>>>
>>> More generally, for external toolchains, the correct symbolic link
>is
>>> from (usr/)${ARCH_LIB_DIR} to lib. For internal toolchains, current
>>> toolchains always use either lib32 or lib64.
>>>
>>> Fix the problem as follows:
>>> - create symlink creation helpers in toolchain/helpers.mk
>>> - for external toolchains, call these helpers based on ARCH_LIB_DIR
>>> - for internal toolchains, call these helpers based on the existing
>>>   fixed lib32/lib64 logic, moved from Makefile
>>> - to fix build order problems, add the correct dependency on
>>>   $(BUILD_DIR) from $(BUILD_DIR)/.root
>>
>>  It's not clear to us which build order problems are solved by this,
>and
>> especially how these build order problems are introduced by this
>patch... Could
>> you explain that a little?
>
>As you may imagine, my memory of these issues is not so crisp anymore,
>but IIRC without these build-order changes it would not build
>correctly. I guess I was using 'make clean toolchain' and it would
>fail, but I would need to retest explicitly to be sure.
>
>>
>>>
>>> Signed-off-by: Thomas De Schampheleire
><thomas.de.schampheleire@gmail.com>
>>>
>>> ---
>>> v3:
>>> - update commit message wrapping
>>> - change dependency on $(BUILD_DIR) to a order-only dependency
>>> v2:
>>> - fix 'lib32-fp' leftover in toolchain-buildroot
>>> - silence commands creating symlink with $(Q)
>>> - fix case where ARCH_LIB_DIR is 'lib'
>>>
>>> Note: the handling in the internal toolchain is a bit awkward
>because it
>>> explicitly adds a new target, but I don't see a much better way: it
>must
>>> be done _before_ the toolchain is being built. The entire logic
>cannot
>>> be done in Makefile as ARCH_LIB_DIR is not available there.
>>> ---
>>>  Makefile                                             | 14
>+-------------
>>>  toolchain/helpers.mk                                 | 16
>++++++++++++++++
>>>  toolchain/toolchain-buildroot/toolchain-buildroot.mk | 11
>+++++++++++
>>>  toolchain/toolchain-external/toolchain-external.mk   | 12
>++++++++++++
>>>  4 files changed, 40 insertions(+), 13 deletions(-)
>>>
>>> diff --git a/Makefile b/Makefile
>>> index 338c992..de202b0 100644
>>> --- a/Makefile
>>> +++ b/Makefile
>>> @@ -449,20 +449,10 @@ world: target-post-image
>>>  $(BUILD_DIR) $(HOST_DIR) $(BINARIES_DIR) $(LEGAL_INFO_DIR)
>$(REDIST_SOURCES_DIR_TARGET) $(REDIST_SOURCES_DIR_HOST):
>>>       @mkdir -p $@
>>>
>>> -# We make a symlink lib32->lib or lib64->lib as appropriate
>>> -# MIPS64/n32 requires lib32 even though it's a 64-bit arch.
>>> -ifeq ($(BR2_ARCH_IS_64)$(BR2_MIPS_NABI32),y)
>>> -LIB_SYMLINK = lib64
>>> -else
>>> -LIB_SYMLINK = lib32
>>> -endif
>>
>>  Yeah, it's good to see this disappear from top-level Makefile!
>>
>>> -
>>>  $(STAGING_DIR):
>>>       @mkdir -p $(STAGING_DIR)/bin
>>>       @mkdir -p $(STAGING_DIR)/lib
>>> -     @ln -snf lib $(STAGING_DIR)/$(LIB_SYMLINK)
>>>       @mkdir -p $(STAGING_DIR)/usr/lib
>>> -     @ln -snf lib $(STAGING_DIR)/usr/$(LIB_SYMLINK)
>>>       @mkdir -p $(STAGING_DIR)/usr/include
>>>       @mkdir -p $(STAGING_DIR)/usr/bin
>>>       @ln -snf $(STAGING_DIR) $(BASE_DIR)/staging
>>> @@ -475,15 +465,13 @@ RSYNC_VCS_EXCLUSIONS = \
>>>       --exclude .svn --exclude .git --exclude .hg --exclude .bzr \
>>>       --exclude CVS
>>>
>>> -$(BUILD_DIR)/.root:
>>> +$(BUILD_DIR)/.root: | $(BUILD_DIR)
>>>       mkdir -p $(TARGET_DIR)
>>>       rsync -a --ignore-times $(RSYNC_VCS_EXCLUSIONS) \
>>>               --chmod=Du+w --exclude .empty --exclude '*~' \
>>>               $(TARGET_SKELETON)/ $(TARGET_DIR)/
>>>       $(INSTALL) -m 0644 support/misc/target-dir-warning.txt
>$(TARGET_DIR_WARNING_FILE)
>>> -     @ln -snf lib $(TARGET_DIR)/$(LIB_SYMLINK)
>>>       @mkdir -p $(TARGET_DIR)/usr
>>> -     @ln -snf lib $(TARGET_DIR)/usr/$(LIB_SYMLINK)
>>>       touch $@
>>>
>>>  $(TARGET_DIR): $(BUILD_DIR)/.root
>>> diff --git a/toolchain/helpers.mk b/toolchain/helpers.mk
>>> index 3121da4..b4879e0 100644
>>> --- a/toolchain/helpers.mk
>>> +++ b/toolchain/helpers.mk
>>> @@ -1,5 +1,21 @@
>>>  # This Makefile fragment declares toolchain related helper
>functions.
>>>
>>> +# Create the necessary symlink from (usr/)lib32|lib64|lib32-fp|...
>to lib
>>> +# In general, for external toolchains, the correct link name is
>$ARCH_LIB_DIR.
>>> +create_staging_lib_symlink = \
>>> +     LIB_SYMLINK="$(strip $1)" ; \
>>> +     if [ "$${LIB_SYMLINK}" != "lib" ]; then \
>>> +             ln -snf lib $(STAGING_DIR)/$${LIB_SYMLINK} ; \
>>> +             ln -snf lib $(STAGING_DIR)/usr/$${LIB_SYMLINK} ; \
>>> +     fi
>>> +
>>> +create_target_lib_symlink = \
>>> +     LIB_SYMLINK="$(strip $1)" ; \
>>> +     if [ "$${LIB_SYMLINK}" != "lib" ]; then \
>>> +         ln -snf lib $(TARGET_DIR)/$${LIB_SYMLINK} ; \
>>> +         ln -snf lib $(TARGET_DIR)/usr/$${LIB_SYMLINK} ; \
>>> +     fi
>>
>>  These two functions are identical except for the target dir, so
>create just one
>> function with the directory as a second parameter.
>
>OK
>
>>
>>> +
>>>  # The copy_toolchain_lib_root function copies a toolchain library
>and
>>>  # its symbolic links from the sysroot directory to the target
>>>  # directory. Note that this function is used both by the external
>>> diff --git a/toolchain/toolchain-buildroot/toolchain-buildroot.mk
>b/toolchain/toolchain-buildroot/toolchain-buildroot.mk
>>> index b30cc33..3ccb030 100644
>>> --- a/toolchain/toolchain-buildroot/toolchain-buildroot.mk
>>> +++ b/toolchain/toolchain-buildroot/toolchain-buildroot.mk
>>> @@ -12,6 +12,17 @@ BR_LIBC = $(call
>qstrip,$(BR2_TOOLCHAIN_BUILDROOT_LIBC))
>>>
>>>  TOOLCHAIN_BUILDROOT_DEPENDENCIES = host-gcc-final
>>>
>>> +ifeq ($(BR2_ARCH_IS_64)$(BR2_MIPS_NABI32),y)
>>
>>  The comment about MIPS64/n32 should have been retained here.
>
>True.
>
>>
>>> +LIB_SYMLINK = lib64
>>> +else
>>> +LIB_SYMLINK = lib32
>>> +endif
>>
>>  Since now it is something specific to this .mk file, perhaps it
>should be
>> prefixed with TOOLCHAIN_BUILDROOT_
>
>OK.
>
>>
>>> +
>>> +host-gcc-final: create-lib-symlinks
>>
>>  This is not just awkward, it also breaks top-level parallel build.
>At least, if
>> host-gcc-final really does need this to be done. In top-level
>parallel build,
>> the order between the dependencies is not set, so it's possible that
>the
>> symlinks are only created after the build of gcc has already started.
>
>Here I don't follow: the line above expresses that host-gcc-final
>needs create-lib-symlinks. So even with top-level parallel build,
>_first_ create-lib-symlinks is executed, and only then host-gcc-final.
>
>Your statement seems to refer to cases like:
>
>foo: bar baz
>
>Where bar and baz can indeed be executed in parallel.
>Or I'm misunderstanding you or the situation.
>
>
>> Of course,
>> it's vanishingly unlikely that it will not yet have finished by the
>time the gcc
>> install step starts... Actually, we wonder if it is really needed
>before
>> gcc-final, or even before the libc? Because the way that make
>evaluates things
>> in the non-parallel case, this step would have been done before
>anything else,
>> even before host-binutils...
>
>For external toolchains the links are created after extraction, when
>installing the toolchain in target and staging.
>For internal toolchain I don't remember if it needs to be done before
>host-gcc-final, or if it's enough that it is done after host-gcc-final
>but I couldn't find a better way to achieve that because
>host-gcc-final is the target used for toolchain/toolchain-buildroot,
>so there wasn't a lot of hooking possibility without changing a lot of
>code. I would need to retest to be sure.
>
>>
>>  If it really should be done before host-gcc-final, the full solution
>would be
>> to add this as a post-install hook to the libc. You could do
>something like this:
>>
>> $(call uppercase,$(BR_LIBC))_POST_INSTALL_STAGING_HOOKS += \
>>         $(call create_staging_lib_symlink,$(LIB_SYMLINK))
>>
>> Isn't that beautiful :-) This also has the advantage of splitting the
>staging
>> and target installs into their appropriate locations.
>>
>>  Alternatively, you could add a tiny package without source that does
>this and
>> add that as a dependency to host-gcc-final.
>>
>>
>>
>>  Do you still have the energy to make some changes and resubmit?
>
>I'll see if I can look at some of this tomorrow but I can't make any
>promises. But if you happen to be in the heat of the moment tonight
>and can't resist reworking some of this then be my guest :-)

'if you happen to be in the zone tonight' would probably qualify as better use of English expressions, but I'm sure you got the idea :-)
Thomas De Schampheleire July 14, 2015, 8:09 a.m. UTC | #4
On Mon, Jul 13, 2015 at 6:57 PM, Arnout Vandecappelle <arnout@mind.be> wrote:
>  Hi Thomas,
>
>  Sorry that it is taking so long to make progress on this, but the external
> toolchain stuff is, as you know, horribly demotivating... We've spent quite a
> bit of time to understand what this patch does and how it could be done better...
>
> On 02/18/15 12:36, Thomas De Schampheleire wrote:
>> From: Thomas De Schampheleire <thomas.de.schampheleire@gmail.com>
>>
>> Currently, following symbolic links are created in both target and
>> staging directories:
>> - lib(32|64) --> lib
>> - usr/lib(32|64) --> lib
>>
>> The decision for lib32 or lib64 is based on the target architecture
>> configuration in buildroot (BR2_ARCH_IS_64).
>>
>> In at least one case this is not correct: when building for a Cavium Octeon
>> III processor using the toolchain from the Cavium Networks SDK, and
>> specifying -march=octeon3 in BR2_TARGET_OPTIMIZATION, libraries are expected
>> in directory 'lib32-fp' rather than 'lib32' (likewise for lib64-fp).
>>
>> More generally, for external toolchains, the correct symbolic link is
>> from (usr/)${ARCH_LIB_DIR} to lib. For internal toolchains, current
>> toolchains always use either lib32 or lib64.
>>
>> Fix the problem as follows:
>> - create symlink creation helpers in toolchain/helpers.mk
>> - for external toolchains, call these helpers based on ARCH_LIB_DIR
>> - for internal toolchains, call these helpers based on the existing
>>   fixed lib32/lib64 logic, moved from Makefile
>> - to fix build order problems, add the correct dependency on
>>   $(BUILD_DIR) from $(BUILD_DIR)/.root
>
>  It's not clear to us which build order problems are solved by this, and
> especially how these build order problems are introduced by this patch... Could
> you explain that a little?

If you use this patch but revert the order-only dependency of .root on
$(BUILD_DIR), then attempt building an internal toolchain using 'make
clean toolchain', output is:

rm -rf /repo/tdescham/reborn/buildroot-git/output/target
/repo/tdescham/reborn/buildroot-git/output/images
/repo/tdescham/reborn/buildroot-git/output/host \
                /repo/tdescham/reborn/buildroot-git/output/build
/repo/tdescham/reborn/buildroot-git/output/staging \
                /repo/tdescham/reborn/buildroot-git/output/legal-info
/repo/tdescham/reborn/buildroot-git/output/graphs
mkdir -p /repo/tdescham/reborn/buildroot-git/output/target
rsync -a --ignore-times --exclude .svn --exclude .git --exclude .hg
--exclude .bzr --exclude CVS \
                --chmod=u=rwX,go=rX --exclude .empty --exclude '*~' \
                /repo/tdescham/reborn/buildroot-git/system/skeleton/
/repo/tdescham/reborn/buildroot-git/output/target/
/usr/bin/install -m 0644 support/misc/target-dir-warning.txt
/repo/tdescham/reborn/buildroot-git/output/target/THIS_IS_NOT_YOUR_ROOT_FILESYSTEM
touch /repo/tdescham/reborn/buildroot-git/output/build/.root
touch: cannot touch
`/repo/tdescham/reborn/buildroot-git/output/build/.root': No such file
or directory
make: *** [/repo/tdescham/reborn/buildroot-git/output/build/.root] Error 1


For external toolchains there is no issue.
It is caused by the fact that the patch adds a dependency on
$(TARGET_DIR) to host-gcc-final via create-lib-symlinks, and
$(TARGET_DIR) has a dependency on $(BUILD_DIR)/.root (see Makefile).

If the host-gcc-final change is fixed in another way (I have to check)
this may not be needed after all. However, technically I think the
expression of the dependency is correct: $(BUILD_DIR)/.root indeed
needs BUILD_DIR first. Alternatively you could add a dependency on
'dirs' somewhere.

/Thomas
Arnout Vandecappelle July 14, 2015, 8:54 a.m. UTC | #5
On 07/14/15 10:09, Thomas De Schampheleire wrote:
> On Mon, Jul 13, 2015 at 6:57 PM, Arnout Vandecappelle <arnout@mind.be> wrote:
>>  Hi Thomas,
>>
>>  Sorry that it is taking so long to make progress on this, but the external
>> toolchain stuff is, as you know, horribly demotivating... We've spent quite a
>> bit of time to understand what this patch does and how it could be done better...
>>
>> On 02/18/15 12:36, Thomas De Schampheleire wrote:
[snip]
>>> - to fix build order problems, add the correct dependency on
>>>   $(BUILD_DIR) from $(BUILD_DIR)/.root
>>
>>  It's not clear to us which build order problems are solved by this, and
>> especially how these build order problems are introduced by this patch... Could
>> you explain that a little?
[snip]
> It is caused by the fact that the patch adds a dependency on
> $(TARGET_DIR) to host-gcc-final via create-lib-symlinks, and
> $(TARGET_DIR) has a dependency on $(BUILD_DIR)/.root (see Makefile).
> 
> If the host-gcc-final change is fixed in another way (I have to check)
> this may not be needed after all. However, technically I think the
> expression of the dependency is correct: $(BUILD_DIR)/.root indeed
> needs BUILD_DIR first. Alternatively you could add a dependency on
> 'dirs' somewhere.

 Or add an mkdir -p $(BUILD_DIR) in the commands of $(BUILD_DIR)/.root itself.
I'm personally a bit opposed against having directories as dependencies,
precisely because of the need for order-only dependencies that you also discovered.

 And I think that could be a separate patch - it may be a problem for top-level
parallel build as well, and it can be merged quickly.

 Regards,
 Arnout
Arnout Vandecappelle July 14, 2015, 10 p.m. UTC | #6
[Now I understand Thomas why you didn't understand what I was talking about on
IRC - seems I forgot to send this mail...]

On 07/13/15 22:19, Thomas De Schampheleire wrote:
> On Mon, Jul 13, 2015 at 6:57 PM, Arnout Vandecappelle <arnout@mind.be> wrote:
>>  Hi Thomas,
>>
>>  Sorry that it is taking so long to make progress on this, but the external
>> toolchain stuff is, as you know, horribly demotivating... We've spent quite a
>> bit of time to understand what this patch does and how it could be done better...
>>
>> On 02/18/15 12:36, Thomas De Schampheleire wrote:
>>> From: Thomas De Schampheleire <thomas.de.schampheleire@gmail.com>
>>>
>>> Currently, following symbolic links are created in both target and
>>> staging directories:
>>> - lib(32|64) --> lib
>>> - usr/lib(32|64) --> lib
>>>
>>> The decision for lib32 or lib64 is based on the target architecture
>>> configuration in buildroot (BR2_ARCH_IS_64).
>>>
>>> In at least one case this is not correct: when building for a Cavium Octeon
>>> III processor using the toolchain from the Cavium Networks SDK, and
>>> specifying -march=octeon3 in BR2_TARGET_OPTIMIZATION, libraries are expected
>>> in directory 'lib32-fp' rather than 'lib32' (likewise for lib64-fp).
>>>
>>> More generally, for external toolchains, the correct symbolic link is
>>> from (usr/)${ARCH_LIB_DIR} to lib. For internal toolchains, current
>>> toolchains always use either lib32 or lib64.
>>>
>>> Fix the problem as follows:
>>> - create symlink creation helpers in toolchain/helpers.mk
>>> - for external toolchains, call these helpers based on ARCH_LIB_DIR
>>> - for internal toolchains, call these helpers based on the existing
>>>   fixed lib32/lib64 logic, moved from Makefile
>>> - to fix build order problems, add the correct dependency on
>>>   $(BUILD_DIR) from $(BUILD_DIR)/.root
>>
>>  It's not clear to us which build order problems are solved by this, and
>> especially how these build order problems are introduced by this patch... Could
>> you explain that a little?
> 
> As you may imagine, my memory of these issues is not so crisp anymore,
> but IIRC without these build-order changes it would not build
> correctly. I guess I was using 'make clean toolchain' and it would
> fail, but I would need to retest explicitly to be sure.
> 
>>
>>>
>>> Signed-off-by: Thomas De Schampheleire <thomas.de.schampheleire@gmail.com>
[snip]
>>> +host-gcc-final: create-lib-symlinks
>>
>>  This is not just awkward, it also breaks top-level parallel build. At least, if
>> host-gcc-final really does need this to be done. In top-level parallel build,
>> the order between the dependencies is not set, so it's possible that the
>> symlinks are only created after the build of gcc has already started.
> 
> Here I don't follow: the line above expresses that host-gcc-final
> needs create-lib-symlinks. 

 Semantically, yes. But technically, it doesn't. host-gcc-final is a PHONY
target that depends on the actual build steps of gcc. So in parallel build,
create-lib-symlinks will be executed in parallel with host-gcc-final-install.

> So even with top-level parallel build,
> _first_ create-lib-symlinks is executed, and only then host-gcc-final.
> 
> Your statement seems to refer to cases like:
> 
> foo: bar baz
> 
> Where bar and baz can indeed be executed in parallel.

 That's exactly the case we are in.

In toolchain-buildroot.mk:

host-gcc-final: create-lib-symlinks

Generated from generic-package:

host-gcc-final: host-gcc-final-install

and no commands.

> Or I'm misunderstanding you or the situation.
> 
> 
>> Of course,
>> it's vanishingly unlikely that it will not yet have finished by the time the gcc
>> install step starts... Actually, we wonder if it is really needed before
>> gcc-final, or even before the libc? Because the way that make evaluates things
>> in the non-parallel case, this step would have been done before anything else,
>> even before host-binutils...
> 
> For external toolchains the links are created after extraction, when
> installing the toolchain in target and staging.
> For internal toolchain I don't remember if it needs to be done before
> host-gcc-final, or if it's enough that it is done after host-gcc-final
> but I couldn't find a better way to achieve that because
> host-gcc-final is the target used for toolchain/toolchain-buildroot,
> so there wasn't a lot of hooking possibility without changing a lot of
> code. I would need to retest to be sure.

 I was actually surprised that it was even needed for the internal toolchain
itself, I thought we refactored the symlinking of the external toolchain just to
make things consistent. The current symlink was introduced in 5628776c4, before
that there was only some (partially broken) symlinking for the external toolchain.

>>
>>  If it really should be done before host-gcc-final, the full solution would be
>> to add this as a post-install hook to the libc. You could do something like this:
>>
>> $(call uppercase,$(BR_LIBC))_POST_INSTALL_STAGING_HOOKS += \
>>         $(call create_staging_lib_symlink,$(LIB_SYMLINK))
>>
>> Isn't that beautiful :-) This also has the advantage of splitting the staging
>> and target installs into their appropriate locations.
>>
>>  Alternatively, you could add a tiny package without source that does this and
>> add that as a dependency to host-gcc-final.
>>
>>
>>
>>  Do you still have the energy to make some changes and resubmit?
> 
> I'll see if I can look at some of this tomorrow but I can't make any
> promises. But if you happen to be in the heat of the moment tonight
> and can't resist reworking some of this then be my guest :-)
> I'll log into IRC tomorrow...

 We actually have other cats to whip :-) and to be honest, nobody is really
excited about touching the external toolchain stuff. I'll shout in the room here
and see if anyone jumps up.

 Regards,
 Arnout

> 
> Thanks for the feedback,
> Thomas
>
diff mbox

Patch

diff --git a/Makefile b/Makefile
index 338c992..de202b0 100644
--- a/Makefile
+++ b/Makefile
@@ -449,20 +449,10 @@  world: target-post-image
 $(BUILD_DIR) $(HOST_DIR) $(BINARIES_DIR) $(LEGAL_INFO_DIR) $(REDIST_SOURCES_DIR_TARGET) $(REDIST_SOURCES_DIR_HOST):
 	@mkdir -p $@
 
-# We make a symlink lib32->lib or lib64->lib as appropriate
-# MIPS64/n32 requires lib32 even though it's a 64-bit arch.
-ifeq ($(BR2_ARCH_IS_64)$(BR2_MIPS_NABI32),y)
-LIB_SYMLINK = lib64
-else
-LIB_SYMLINK = lib32
-endif
-
 $(STAGING_DIR):
 	@mkdir -p $(STAGING_DIR)/bin
 	@mkdir -p $(STAGING_DIR)/lib
-	@ln -snf lib $(STAGING_DIR)/$(LIB_SYMLINK)
 	@mkdir -p $(STAGING_DIR)/usr/lib
-	@ln -snf lib $(STAGING_DIR)/usr/$(LIB_SYMLINK)
 	@mkdir -p $(STAGING_DIR)/usr/include
 	@mkdir -p $(STAGING_DIR)/usr/bin
 	@ln -snf $(STAGING_DIR) $(BASE_DIR)/staging
@@ -475,15 +465,13 @@  RSYNC_VCS_EXCLUSIONS = \
 	--exclude .svn --exclude .git --exclude .hg --exclude .bzr \
 	--exclude CVS
 
-$(BUILD_DIR)/.root:
+$(BUILD_DIR)/.root: | $(BUILD_DIR)
 	mkdir -p $(TARGET_DIR)
 	rsync -a --ignore-times $(RSYNC_VCS_EXCLUSIONS) \
 		--chmod=Du+w --exclude .empty --exclude '*~' \
 		$(TARGET_SKELETON)/ $(TARGET_DIR)/
 	$(INSTALL) -m 0644 support/misc/target-dir-warning.txt $(TARGET_DIR_WARNING_FILE)
-	@ln -snf lib $(TARGET_DIR)/$(LIB_SYMLINK)
 	@mkdir -p $(TARGET_DIR)/usr
-	@ln -snf lib $(TARGET_DIR)/usr/$(LIB_SYMLINK)
 	touch $@
 
 $(TARGET_DIR): $(BUILD_DIR)/.root
diff --git a/toolchain/helpers.mk b/toolchain/helpers.mk
index 3121da4..b4879e0 100644
--- a/toolchain/helpers.mk
+++ b/toolchain/helpers.mk
@@ -1,5 +1,21 @@ 
 # This Makefile fragment declares toolchain related helper functions.
 
+# Create the necessary symlink from (usr/)lib32|lib64|lib32-fp|... to lib
+# In general, for external toolchains, the correct link name is $ARCH_LIB_DIR.
+create_staging_lib_symlink = \
+	LIB_SYMLINK="$(strip $1)" ; \
+	if [ "$${LIB_SYMLINK}" != "lib" ]; then \
+		ln -snf lib $(STAGING_DIR)/$${LIB_SYMLINK} ; \
+		ln -snf lib $(STAGING_DIR)/usr/$${LIB_SYMLINK} ; \
+	fi
+
+create_target_lib_symlink = \
+	LIB_SYMLINK="$(strip $1)" ; \
+	if [ "$${LIB_SYMLINK}" != "lib" ]; then \
+	    ln -snf lib $(TARGET_DIR)/$${LIB_SYMLINK} ; \
+	    ln -snf lib $(TARGET_DIR)/usr/$${LIB_SYMLINK} ; \
+	fi
+
 # The copy_toolchain_lib_root function copies a toolchain library and
 # its symbolic links from the sysroot directory to the target
 # directory. Note that this function is used both by the external
diff --git a/toolchain/toolchain-buildroot/toolchain-buildroot.mk b/toolchain/toolchain-buildroot/toolchain-buildroot.mk
index b30cc33..3ccb030 100644
--- a/toolchain/toolchain-buildroot/toolchain-buildroot.mk
+++ b/toolchain/toolchain-buildroot/toolchain-buildroot.mk
@@ -12,6 +12,17 @@  BR_LIBC = $(call qstrip,$(BR2_TOOLCHAIN_BUILDROOT_LIBC))
 
 TOOLCHAIN_BUILDROOT_DEPENDENCIES = host-gcc-final
 
+ifeq ($(BR2_ARCH_IS_64)$(BR2_MIPS_NABI32),y)
+LIB_SYMLINK = lib64
+else
+LIB_SYMLINK = lib32
+endif
+
+host-gcc-final: create-lib-symlinks
+create-lib-symlinks: $(STAGING_DIR) $(TARGET_DIR)
+	$(call create_staging_lib_symlink,$(LIB_SYMLINK))
+	$(call create_target_lib_symlink,$(LIB_SYMLINK))
+
 TOOLCHAIN_BUILDROOT_ADD_TOOLCHAIN_DEPENDENCY = NO
 
 $(eval $(virtual-package))
diff --git a/toolchain/toolchain-external/toolchain-external.mk b/toolchain/toolchain-external/toolchain-external.mk
index e05957c..16e398c 100644
--- a/toolchain/toolchain-external/toolchain-external.mk
+++ b/toolchain/toolchain-external/toolchain-external.mk
@@ -600,6 +600,16 @@  define TOOLCHAIN_EXTERNAL_INSTALL_SYSROOT_LIBS
 	$(call copy_toolchain_sysroot,$${SYSROOT_DIR},$${ARCH_SYSROOT_DIR},$${ARCH_SUBDIR},$${ARCH_LIB_DIR},$${SUPPORT_LIB_DIR})
 endef
 
+define TOOLCHAIN_EXTERNAL_CREATE_STAGING_LIB_SYMLINK
+	$(Q)ARCH_LIB_DIR="$(call toolchain_find_libdir,$(TOOLCHAIN_EXTERNAL_CC) $(TOOLCHAIN_EXTERNAL_CFLAGS))" ; \
+	$(call create_staging_lib_symlink,$${ARCH_LIB_DIR})
+endef
+
+define TOOLCHAIN_EXTERNAL_CREATE_TARGET_LIB_SYMLINK
+	$(Q)ARCH_LIB_DIR="$(call toolchain_find_libdir,$(TOOLCHAIN_EXTERNAL_CC) $(TOOLCHAIN_EXTERNAL_CFLAGS))" ; \
+	$(call create_target_lib_symlink,$${ARCH_LIB_DIR})
+endef
+
 # Special installation target used on the Blackfin architecture when
 # FDPIC is not the primary binary format being used, but the user has
 # nonetheless requested the installation of the FDPIC libraries to the
@@ -699,6 +709,7 @@  define TOOLCHAIN_EXTERNAL_INSTALL_GDBINIT
 endef
 
 define TOOLCHAIN_EXTERNAL_INSTALL_STAGING_CMDS
+	$(TOOLCHAIN_EXTERNAL_CREATE_STAGING_LIB_SYMLINK)
 	$(TOOLCHAIN_EXTERNAL_INSTALL_SYSROOT_LIBS)
 	$(TOOLCHAIN_EXTERNAL_INSTALL_WRAPPER)
 	$(TOOLCHAIN_EXTERNAL_INSTALL_GDBINIT)
@@ -708,6 +719,7 @@  endef
 # and the target directory, we do everything within the
 # install-staging step, arbitrarily.
 define TOOLCHAIN_EXTERNAL_INSTALL_TARGET_CMDS
+	$(TOOLCHAIN_EXTERNAL_CREATE_TARGET_LIB_SYMLINK)
 	$(TOOLCHAIN_EXTERNAL_INSTALL_TARGET_LIBS)
 	$(TOOLCHAIN_EXTERNAL_INSTALL_BFIN_FDPIC)
 	$(TOOLCHAIN_EXTERNAL_INSTALL_BFIN_FLAT)