Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How does the multilib selection mechanism work these days? #1354

Closed
TommyMurphyTM1234 opened this issue Oct 16, 2023 · 11 comments
Closed

How does the multilib selection mechanism work these days? #1354

TommyMurphyTM1234 opened this issue Oct 16, 2023 · 11 comments

Comments

@TommyMurphyTM1234
Copy link
Collaborator

TommyMurphyTM1234 commented Oct 16, 2023

In the past these files could be used to control the set of multilibs built:

  • multilib-generator: Python script used to generate the contents of t-elf-multilib and/or t-linux-multilib
  • t-elf-multilib: the (default unless overridden) set of multilibs to be built for the bare metal/newlib toolchain
  • t-linux-multilib: the (default unless overridden) set of multilibs to be built for the Linux toolchain

So, it was possible to run the multilib-generator in order to specify a different set of multilibs than specified by the default t-elf-multilib/t-linux-multilib files.

However, as far as I can see, this approach to overriding the contents of t-elf-multilib or t-linux-multilib to change the set of multilibs built no longer works.

I know that configure --with-multilib-generator="..." can be used to override the default set of multilibs built for the bare metal/newlib toolchain.
However, as stated in the README.md, this does not work for the Linux toolchain.
So how can one override the default set of multilibs built for the Linux toolchain?

I see this in the riscv-gnu-toolchain top level Makefile after running configure ... --enable-multilib:

MULTILIB_FLAGS := --enable-multilib
MULTILIB_GEN :=
ifeq ($(MULTILIB_GEN),)
NEWLIB_MULTILIB_NAMES := rv32i-ilp32 rv32iac-ilp32 rv32im-ilp32 rv32imac-ilp32 rv32imafc-ilp32f rv64imac-lp64 rv64imafdc-lp64d
GCC_MULTILIB_FLAGS := $(MULTILIB_FLAGS)
else
NEWLIB_MULTILIB_NAMES := $(shell echo "$(MULTILIB_GEN)" | $(SED) 's/;/\n/g'| $(AWK) '{split($$0,a,"-"); printf "%s-%s ", a[1],a[2]}')
GCC_MULTILIB_FLAGS := $(MULTILIB_FLAGS) --with-multilib-generator="$(MULTILIB_GEN)"
endif
GLIBC_MULTILIB_NAMES := rv32imac-ilp32 rv32imafdc-ilp32d rv64imac-lp64 rv64imafdc-lp64d
GCC_CHECKING_FLAGS :=

However I don't really understand:

  1. How this works?
  2. How the set of multilibs can be controlled/overridden?
  3. How the multilib-generator, t-elf-multilib and t-linux-multilib files relate to this mechanism - if at all?
  4. Why the ifeq ($(MULTILIB_GEN),) check - and subsequent else clause - exist since MULTILIB_GEN always set to nothing by the preceding line?
  5. Shouldn't GLIBC_MULTILIB_NAMES := rv32imac-ilp32 rv32imafdc-ilp32d rv64imac-lp64 rv64imafdc-lp64d perhaps be GLIBC_MULTILIB_NAMES ?= rv32imac-ilp32 rv32imafdc-ilp32d rv64imac-lp64 rv64imafdc-lp64d to allow it to be overridden externally? (And ditto for NEWLIB_MULTILIB_NAMES?)

Can anybody explain how the current multilib build mechanism works and how the set of multilibs built can be controlled?

@TommyMurphyTM1234
Copy link
Collaborator Author

TommyMurphyTM1234 commented Oct 17, 2023

OK - I just realised that I'm probably slightly misguided in looking at the generated Makefile and should probably look at the input Makefile.in and what configure does with that based on the options passed. Let me look at this again from that perspective.

@TommyMurphyTM1234
Copy link
Collaborator Author

TommyMurphyTM1234 commented Oct 18, 2023

Why does this happen - why is the multilib list not identical?

Using --enable-multilib to enable the default set of multilibs:

./configure --prefix=`pwd`/installed-tools --disable-gdb --enable-multilib
make 2>&1 | tee build.log

ls -1d installed-tools/riscv64-unknown-elf/lib/rv*
installed-tools/riscv64-unknown-elf/lib/rv32i
installed-tools/riscv64-unknown-elf/lib/rv32iac
installed-tools/riscv64-unknown-elf/lib/rv32im
installed-tools/riscv64-unknown-elf/lib/rv32imac
installed-tools/riscv64-unknown-elf/lib/rv32imafc
installed-tools/riscv64-unknown-elf/lib/rv64imac
installed-tools/riscv64-unknown-elf/lib/rv64imafdc

 ./installed-tools/bin/riscv64-unknown-elf-gcc -print-multi-lib
.;
rv32i/ilp32;@march=rv32i@mabi=ilp32
rv32im/ilp32;@march=rv32im@mabi=ilp32
rv32iac/ilp32;@march=rv32iac@mabi=ilp32
rv32imac/ilp32;@march=rv32imac@mabi=ilp32
rv32imafc/ilp32f;@march=rv32imafc@mabi=ilp32f
rv64imac/lp64;@march=rv64imac@mabi=lp64
rv64imafdc/lp64d;@march=rv64imafdc@mabi=lp64d

Using --with-multilib-generator to specify the default set of multilibs explicitly:

./configure --prefix=`pwd`/installed-tools --disable-gdb --with-multilib-generator="rv32i-ilp32--;rv32iac-ilp32--;rv32im-ilp32--;rv32imac-ilp32--;rv32imafc-ilp32f--;rv64imac-lp64--;rv64imafdc-lp64d--"
make 2>&1 | tee build.log

ls -1d installed-tools/riscv64-unknown-elf/lib/rv*
installed-tools/riscv64-unknown-elf/lib/rv32i
installed-tools/riscv64-unknown-elf/lib/rv32iac
installed-tools/riscv64-unknown-elf/lib/rv32im
installed-tools/riscv64-unknown-elf/lib/rv32imac
installed-tools/riscv64-unknown-elf/lib/rv32imafc_zicsr
installed-tools/riscv64-unknown-elf/lib/rv64imac

./installed-tools/bin/riscv64-unknown-elf-gcc -print-multi-lib
.;
rv32i/ilp32;@march=rv32i@mabi=ilp32
rv32iac/ilp32;@march=rv32iac@mabi=ilp32
rv32im/ilp32;@march=rv32im@mabi=ilp32
rv32imac/ilp32;@march=rv32imac@mabi=ilp32
rv32imafc_zicsr/ilp32f;@march=rv32imafc_zicsr@mabi=ilp32f
rv64imac/lp64;@march=rv64imac@mabi=lp64

@TommyMurphyTM1234
Copy link
Collaborator Author

TommyMurphyTM1234 commented Oct 18, 2023

Continuing my conversation with myself... :-)

  1. How the multilib-generator, t-elf-multilib and t-linux-multilib files relate to this mechanism - if at all?

Looks like multilib-generator is still needed after all - when building the bare-metal/newlib toolchain using configure --with-multilib-generator="...". In its absence the build fails:

../.././gcc/gcc/config.gcc: line 4679: ../.././gcc/gcc/config/riscv/multilib-generator: No such file or directory
invalid option for --with-multilib-generator
make[1]: *** [Makefile:4557: configure-gcc] Error 1
make[1]: Leaving directory '/home/user/Downloads/issue-1354/build-gcc-newlib-stage1'
make: *** [Makefile:591: stamps/build-gcc-newlib-stage1] Error 2

So far, it seems to me that the t-elf-multilib and t-linux-multilib files may be redundant - removing them from the source base seems to have no adverse impact on building the bare-metal or Linux multilib tools.

@TommyMurphyTM1234
Copy link
Collaborator Author

TommyMurphyTM1234 commented Oct 19, 2023

I tried the following configuration, it works for me. FYI...

MULTILIB_LIST="rv32imac_zicsr_zifencei-ilp32--;rv32imafc_zifencei-ilp32--;rv32imafc_zifencei-ilp32f--;rv32imafdc-ilp32--;rv32imafdc-ilp32f--;rv32imafdc-ilp32d--;rv32imac_zicsr_zifencei_zba_zbb_zbc_zbs-ilp32--;rv32imafc_zifencei_zba_zbb_zbc_zbs-ilp32--;rv32imafc_zifencei_zba_zbb_zbc_zbs-ilp32f--;rv32imafdc_zba_zbb_zbc_zbs-ilp32--;rv32imafdc_zba_zbb_zbc_zbs-ilp32f--;rv32imafdc_zba_zbb_zbc_zbs-ilp32d--"
DEFAULT_ARCH=rv32imac_zicsr_zifencei

./configure --target=$TARGET --with-abi=ilp32 --with-arch=${DEFAULT_ARCH} --enable-multilib --with-multilib-generator=${MULTILIB_LIST}  --prefix=${PREFIX} 'CFLAGS_FOR_TARGET=-Os -mstrict-align  -mcmodel=medlow ' 'CXXFLAGS_FOR_TARGET=-Os -mstrict-align   -mcmodel=medlow' LDFLAGS="-static"

Hi @helloeagleyang - I don't really understand the relevance of this in the context of this thread? Maybe you can explain?

I'm not saying that multilib building doesn't work - I'm trying to understand some nuances of the current mechanisms for controlling which multilibs are built and how. This is ongoing and I am using this issue thread to keep track of progress.

At this stage my key questions are:

  1. Are t-elf-multilib/t-linux-multilib redundant? Seems to me that they are and could be removed upstream.
  2. How can the list of Linux multilibs be modified? Seems to me that the only way right now is to manually edit the configure generated Makefile to change the value of GLIBC_MULTILIB_NAMES and there is no way to pass a custom list in otherwise?
  3. Why couldn't --with-multilib-generator (or a suitably named equivalent) be used to pass in a custom list of multilibs but use the multilib mechanism that does not call out to multilib-generator (thus obviating the need for this script too) to build them for both the bare-metal and Linux toolchains thereby making things more consistent overall? I am still looking into this and, if possible, will come up with a PR for it.
  4. Why does using --with-multilib-generator to specify the default set of bare-metal/newlib multilibs built if just --enable-multilib is specified not result in identical results?

@TommyMurphyTM1234
Copy link
Collaborator Author

Update regarding these files:

  1. multilib-generator: still required when --with-multilib-generator is used to specify a custom set of multilibs to be built for the bare-metal/newlib toolchain. If removed then the following error occurs:
../.././gcc/gcc/config.gcc: line 4679: ../.././gcc/gcc/config/riscv/multilib-generator: No such file or directory
invalid option for --with-multilib-generator
make[1]: *** [Makefile:4557: configure-gcc] Error 1
make[1]: Leaving directory '/home/user/Downloads/issue-1354/build-gcc-newlib-stage1'
make: *** [Makefile:591: stamps/build-gcc-newlib-stage1] Error 2
  1. t-elf-multilib: doesn't seem to be required - removing it has no adverse impact on the building of the non-multilib or multilib (--enable-multilib or --with-multilib-generator) bare-metal/newlib toolchain

  2. t-linux-multilib: if removed then the following error occurs when building the multilib enabled Linux toolchain:

for symbol in __GI___pthread_disable_asynccancel __GI___pthread_enable_asynccancel __libc_assert_fail __pthread_disable_asynccancel __pthread_enable_asynccancel calloc free malloc realloc  __stack_chk_fail __stack_chk_fail_local; do \
        echo ".globl $symbol"; \
        echo "$symbol:"; \
done | riscv64-unknown-linux-gnu-gcc -march=rv32imac -mabi=ilp32 -o /home/user/Downloads/test/build-glibc-linux-rv32imac-ilp32/elf/librtld.mapT.o -Werror=undef -Wa,--noexecstack  -c -x assembler -
riscv64-unknown-linux-gnu-gcc -march=rv32imac -mabi=ilp32   -nostdlib -nostartfiles -r -o /home/user/Downloads/test/build-glibc-linux-rv32imac-ilp32/elf/librtld.map.o /home/user/Downloads/test/build-glibc-linux-rv32imac-ilp32/elf/librtld.mapT.o '-Wl,-(' /home/user/Downloads/test/build-glibc-linux-rv32imac-ilp32/elf/dl-allobjs.os /home/user/Downloads/test/build-glibc-linux-rv32imac-ilp32/libc_pic.a -lgcc '-Wl,-)' -Wl,-Map,/home/user/Downloads/test/build-glibc-linux-rv32imac-ilp32/elf/librtld.mapT
/home/user/Downloads/test/installed-tools/lib/gcc/riscv64-unknown-linux-gnu/13.2.0/../../../../riscv64-unknown-linux-gnu/bin/ld: /home/user/Downloads/test/installed-tools/lib/gcc/riscv64-unknown-linux-gnu/13.2.0/libgcc.a(div.o): ABI is incompatible with that of the selected emulation:
  target emulation `elf64-littleriscv' does not match `elf32-littleriscv'
/home/user/Downloads/test/installed-tools/lib/gcc/riscv64-unknown-linux-gnu/13.2.0/../../../../riscv64-unknown-linux-gnu/bin/ld: failed to merge target specific data of file /home/user/Downloads/test/installed-tools/lib/gcc/riscv64-unknown-linux-gnu/13.2.0/libgcc.a(div.o)
/home/user/Downloads/test/installed-tools/lib/gcc/riscv64-unknown-linux-gnu/13.2.0/../../../../riscv64-unknown-linux-gnu/bin/ld: attempt to do relocatable link with elf64-littleriscv input and elf32-littleriscv output
/home/user/Downloads/test/installed-tools/lib/gcc/riscv64-unknown-linux-gnu/13.2.0/../../../../riscv64-unknown-linux-gnu/bin/ld: /home/user/Downloads/test/installed-tools/lib/gcc/riscv64-unknown-linux-gnu/13.2.0/libgcc.a(div.o): file class ELFCLASS64 incompatible with ELFCLASS32
/home/user/Downloads/test/installed-tools/lib/gcc/riscv64-unknown-linux-gnu/13.2.0/../../../../riscv64-unknown-linux-gnu/bin/ld: final link failed: file in wrong format
collect2: error: ld returned 1 exit status
make[3]: *** [Makefile:1285: /home/user/Downloads/test/build-glibc-linux-rv32imac-ilp32/elf/librtld.map] Error 1
make[3]: Leaving directory '/home/user/Downloads/test/glibc/elf'
make[2]: *** [Makefile:484: elf/subdir_lib] Error 2
make[2]: Leaving directory '/home/user/Downloads/test/glibc'
make[1]: *** [Makefile:9: all] Error 2
make[1]: Leaving directory '/home/user/Downloads/test/build-glibc-linux-rv32imac-ilp32'
make: *** [Makefile:389: stamps/build-glibc-linux-rv32imac-ilp32] Error 2

@zqb-all
Copy link
Contributor

zqb-all commented Nov 22, 2023

@TommyMurphyTM1234 Thank you for the information about multilib

I want to build bitmanip multilib, just like #1215 , I modify

glibc_multilib_names="rv32imac-ilp32 rv32imafdc-ilp32d rv64imac-lp64 rv64imafdc-lp64d"

and
[AC_SUBST(glibc_multilib_names,"rv32imac-ilp32 rv32imafdc-ilp32d rv64imac-lp64 rv64imafdc-lp64d")],

add rv64imafdc_zba_zbb_zbc_zbs-lp64d to them.

Then after configure, Makefile will contain

GLIBC_MULTILIB_NAMES := rv32imac-ilp32 rv32imafdc-ilp32d rv64imac-lp64 rv64imafdc-lp64d rv64imafdc_zba_zbb_zbc_zbs-lp64d

Just like the hack here: #1215 (comment)

Then after make linux,build dir contains subdir build-glibc-linux-rv64imafdc_zba_zbb_zbc_zbs-lp64d, which contains the bitmanip lib that I want.

But finally -print-multi-lib don't show any about zba_zbb_zbc_zbs

$xxx/bin/riscv64-unknown-linux-gnu-gcc -print-multi-lib
.;
lib32/ilp32;@march=rv32imac@mabi=ilp32
lib32/ilp32d;@march=rv32imafdc@mabi=ilp32d
lib64/lp64;@march=rv64imac@mabi=lp64
lib64/lp64d;@march=rv64imafdc@mabi=lp64d

Some question:

  1. how to let riscv64-unknown-linux-gnu-gcc -print-multi-lib know zba_zbb_zbc_zbs ?
  2. build-glibc-linux-rv64imafdc_zba_zbb_zbc_zbs-lp64d now install to sysroot/lib64/lp64d, should I change it to another dir , such as sysroot/lib64_zba_zbb_zbc_zbs/lp64d?
  3. when I have a new dir like sysroot/lib64_zba_zbb_zbc_zbs/lp64d, how to let gcc know and use it?

@zqb-all
Copy link
Contributor

zqb-all commented Nov 22, 2023

commit about multilib path in GCC :gcc-mirror/gcc@17d683d

@TommyMurphyTM1234
Copy link
Collaborator Author

TommyMurphyTM1234 commented Nov 22, 2023

@TommyMurphyTM1234 Thank you for the information about multilib

My focus so far has mainly been on the bare metal toolchain.
Unfortunately I have not finished my investigations and formulating my questions but I have found the whole area very confusing.
In the past one could control what multilibs were built for both the bare metal and Linux toolchains by using multilib-generator to override the default contents of t-elf-multilib and t-linux-multilib. But that no longer seems to work.

And that's before even touching on more recent changes such as this and other related PRs which may be relevant to controlling what multilibs are built?

And maybe also the sort of upstream patch that you mentioned above.

I want to build bitmanip multilib, just like #1215 , I modify

glibc_multilib_names="rv32imac-ilp32 rv32imafdc-ilp32d rv64imac-lp64 rv64imafdc-lp64d"

and

[AC_SUBST(glibc_multilib_names,"rv32imac-ilp32 rv32imafdc-ilp32d rv64imac-lp64 rv64imafdc-lp64d")],

add rv64imafdc_zba_zbb_zbc_zbs-lp64d to them.

Then after configure, Makefile will contain

GLIBC_MULTILIB_NAMES := rv32imac-ilp32 rv32imafdc-ilp32d rv64imac-lp64 rv64imafdc-lp64d rv64imafdc_zba_zbb_zbc_zbs-lp64d

Just like the hack here: #1215 (comment)

Then after make linux,build dir contains subdir build-glibc-linux-rv64imafdc_zba_zbb_zbc_zbs-lp64d, which contains the bitmanip lib that I want.

But finally -print-multi-lib don't show any about zba_zbb_zbc_zbs

As far as I can see the build will always only build the default set of multilibs no matter what tweaking is done.

Edit: apologies - configure ... --with-multilib-generator=... does allow the multilib list to be controlled for the bare metal toolchain but, so far, I have not been able to identify a way to control the multilib list for the GCC Linux toolchain (never mind other variants such as LLVM, GCC/Musl etc.).

$xxx/bin/riscv64-unknown-linux-gnu-gcc -print-multi-lib
.;
lib32/ilp32;@march=rv32imac@mabi=ilp32
lib32/ilp32d;@march=rv32imafdc@mabi=ilp32d
lib64/lp64;@march=rv64imac@mabi=lp64
lib64/lp64d;@march=rv64imafdc@mabi=lp64d

Perhaps as a stopgap can you build a toolchain targeting your required arch/abi directly rather than via multilibs?
E.g.

./configure --prefix=... --with-arch=rv64imafdc_zba_zbb_zbc_zbs --with-abi=lp64d [--enable-multilib]

@zqb-all
Copy link
Contributor

zqb-all commented Nov 22, 2023

Perhaps as a stopgap can you build a toolchain targeting your required arch/abi directly rather than via multilibs?

Yes, I plan to do this if I can't find a good way to build multilib. Thanks for your advice.

@TommyMurphyTM1234
Copy link
Collaborator Author

Perhaps as a stopgap can you build a toolchain targeting your required arch/abi directly rather than via multilibs?

Yes, I plan to do this if I can't find a good way to build multilib. Thanks for your advice.

FWIW this is what I got:

git clone https://github.com/riscv-collab/riscv-gnu-toolchain issue-1354
cd issue-1354
./configure --prefix=`pwd`/installed-tools --with-arch=rv64imafdc_zba_zbb_zbc_zbs --with-abi=lp64d --enable-multilib
make linux 2>&1 | tee build.log

./installed-tools/bin/riscv64-unknown-linux-gnu-gcc -dumpspecs
...
*multilib_defaults:
march=rv64imafdc_zicsr_zba_zbb_zbc_zbs mabi=lp64d
...

./installed-tools/bin/riscv64-unknown-linux-gnu-gcc -print-multi-lib
.;
lib32/ilp32;@march=rv32imac@mabi=ilp32
lib32/ilp32d;@march=rv32imafdc@mabi=ilp32d
lib64/lp64;@march=rv64imac@mabi=lp64
lib64/lp64d;@march=rv64imafdc@mabi=lp64d

@TommyMurphyTM1234
Copy link
Collaborator Author

Since this issue isn't attracting any useful feedback I'm going to close it. It'll obviously remain as a closed issue for future reference and if there are more specific/focused issues with multilib build options then I will log separate issues for these as needed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants