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

Fix TI C28x (C2000, etc.) support #13681

Draft
wants to merge 4 commits into
base: master
Choose a base branch
from

Conversation

EngJay
Copy link

@EngJay EngJay commented Sep 15, 2024

Summary

The purpose of this PR is to enable building for TI C28x targets with Meson without workarounds and un-mesonic ways.

I've looked through the implementation of the support for TI C28x currently in Meson and it appears workarounds have been used to avoid dealing with these issues directly, like including the arg -llibc.a to the linker args in the cross file for the MSP430 and using linker command files that can include the runtime support library rather than doing it the Mesonic way.

The existing support for TI C28x cross compilation (C2000, C6000, etc.) omits the compiler args that are required to be included in the linker command for TI C28x and formats the names of static libs incorrectly. An example that demonstrates the issue has been created as a repo with a Docker image.

Compiler args not included in linker command

For example, the arg --abi=eabi is needed when compiling source files but also when linking since libraries being linked in and linker scripts have logic that depend on the macros set by the compiler / linker. If this arg is not included as a compiler arg when running the linker with the -z flag, linking fails since the linker fails to confirm the ABI is correct for everything and the wrong elements are included in some places since the ABI-related macros aren't set.

A conditional has been added to the generate_link() method to populate the Ninja $ARGS variable with the compiler args when generating the linking command.

Static lib names are formatted incorrectly

When linking in static libraries, the TI C28x family of compilers requires the full name of the static library be included rather than just the name of the library with the preceding lib and suffix removed.

Currently, for the static lib libc.a with a TI C28x compiler, Meson adds the flag -lc, with which linking fails because the linker doesn't find the lib. Also, the runtime support libraries for this family use a suffix of .lib without lib prepended to the name. The format needed is -llibc.a for the linking command to work. When linking in a specific runtime support library rather than the libc.a index library, the arg needed is like this, -lrts2800_fpu32_eabi.lib.

Meson's find_library() finds the lib but the linker fails to find it because of the format of the arg added by Meson.

# This is faulty because it adds a flag `-lc` at the end of the linker args but
# the C28x compiler expects it in the form `-llibc.a`.
#
cc = meson.get_compiler('c')
c2000_libc = cc.find_library('c', dirs: ti_c28x_c2000_cgt_dir / 'lib', static: true)
FAILED: src/example-i2c-ti-lp-f28379d-bme280.out 
cl2000 --c99 -O2 '--define=RELEASE -DNDEBUG' --cla_support=cla1 --float_support=fpu32 --tmu_support=tmu0 --vcu_support=vcu2 --diag_suppress=10063 --diag_warning=225 --diag_wrap=off --display_error_number --abi=eabi --define=F2837xD --define=CPU1 --issue_remarks -v28 -ml -mt -z --output_file=src/example-i2c-ti-lp-f28379d-bme280.out src/example-i2c-ti-lp-f28379d-bme280.out.p/i2c_ex3_external_loopback.c.o src/example-i2c-ti-lp-f28379d-bme280.out.p/device_F2837xD_CodeStartBranch.asm.o src/example-i2c-ti-lp-f28379d-bme280.out.p/device_device.c.o /Users/REDACTED/Projects/embedded-hal-c/examples/ti-lp-f28379d/bme280/src/2837xD_RAM_lnk_cpu1.cmd /Users/REDACTED/Projects/embedded-hal-c/examples/ti-lp-f28379d/bme280/subprojects/c2000ware-core-sdk/driverlib/f2837xd/driverlib/ccs/Release/driverlib_eabi.lib -mmain.map --heap_size=0x200 --stack_size=0x3F8 --warn_sections -i/Applications/ti/ti-cgt-c2000_22.6.1.LTS/lib -i/Applications/ti/ti-cgt-c2000_22.6.1.LTS/include --reread_libs --define=RAM --diag_wrap=off --display_error_number --xml_link_info=example-i2c-ti-f28379d-bme280_linkInfo.xml --entry_point=code_start --rom_model -lc
<Linking>
error #10008-D: cannot find file "c"

 undefined            first referenced                                                                                                                                                       
  symbol                  in file                                                                                                                                                            
 ---------            ----------------                                                                                                                                                       
 __TI_decompress_lzss                                                                                                                                                                        
 __TI_decompress_none                                                                                                                                                                        
 __c28xabi_divf       /Users/REDACTED/Projects/embedded-hal-c/examples/ti-lp-f28379d/bme280/subprojects/c2000ware-core-sdk/driverlib/f2837xd/driverlib/ccs/Release/driverlib_eabi.lib<sysctl.obj>
 _c_int00             src/example-i2c-ti-lp-f28379d-bme280.out.p/device_F2837xD_CodeStartBranch.asm.o  

Using Meson's find_library() fails, however, when trying to use it to find the runtime support libraries since they have a suffix of .lib and no prefix.

cc = meson.get_compiler('c')
c2000_rts_lib = cc.find_library('rts2800_fpu32_eabi', dirs: ti_c28x_c2000_cgt_dir / 'lib', static: true)
../src/meson.build:91:16: ERROR: C static library 'rts2800_fpu32_eabi' not found

TODO solution here.

  • resolves #13768

Details

Populating the compiler args for TI C28x linking

I spent some time attempting to figure out how to get the compiler args into the generate_link() method but resorted to using the guts from the generate_compile_rules() method in generate_link(). I imagine there is a better way to do this but this got it working and I can go from here.

An exception has been added to the generate_link() method of the Ninja backend to populate the $ARGS Ninja variable for the linking rule when the linker ID is cl2000, cl6000, or ti.

Exception added to generate_link().

# Compiler args must be included in TI C28x linker commands and static libs must go last.
if linker.get_id() in {'c2000', 'c6000', 'ti'}:
    for for_machine in MachineChoice:
        clist = self.environment.coredata.compilers[for_machine]
        for langname, compiler in clist.items():
            if langname == 'c' and compiler.get_id() in {'c2000', 'c6000', 'ti'}:
                compile_args = self.generate_basic_compiler_args(target, compiler)
    elem.add_item('ARGS', compile_args)

This change, however, caused a bunch test failures because the StaticLinker class did not have a get_id() method despite having an id, so a method has been added that matches the DynamicLinker class's method.

Addition of method to get ID of static linkers

The changes initially caused many test failures due to the lack of the same method for getting the ID of dynamic linkers on the static linker base class. The same method, get_id(), has now been implemented on the StaticLinker class, too, so the method can be used to identify the linker in places where the instance can be either type.

Exceptions added to format static lib names correctly

TODO

Testing

All tests pass locally except a couple that appear related to my environment. I did not find unit tests for the Ninja backend methods but the CI is passing and I have verified this works successfully with a minimal cross build with C2000. I could provide a self-contained example as a Docker image, if needed, so the minimal example can be run by a reviewer.

@jpakkane
Copy link
Member

jpakkane commented Oct 2, 2024

args += ['$LINK_ARGS', '$in', '$TI_C28X_STATIC_LIBS']

Is it really needed to have some LINK_ARGS before $in? Because if not, then this could be done simpler by doing something like:

if need_to_reorder_commands:
    commands = self.reorder_commands_for_TI_compiler(commands)

just before setting LINK_ARGS.

@EngJay
Copy link
Author

EngJay commented Oct 3, 2024

args += ['$LINK_ARGS', '$in', '$TI_C28X_STATIC_LIBS']

Is it really needed to have some LINK_ARGS before $in? Because if not, then this could be done simpler by doing something like:

if need_to_reorder_commands:
    commands = self.reorder_commands_for_TI_compiler(commands)

just before setting LINK_ARGS.

It appears so, unfortunately.

These are excerpts from the Makefile generated by TI's IDE for the C28x family that shows the order:

...

ORDERED_OBJS += \
"./i2c_ex3_external_loopback.obj" \
"./device/F2837xD_CodeStartBranch.obj" \
"./device/device.obj" \
"../2837xD_RAM_lnk_cpu1.cmd" \
"/Users/REDACTED/ti/C2000Ware_5_03_00_00/driverlib/f2837xd/driverlib/ccs/Debug/driverlib.lib" \
$(GEN_CMDS__FLAG) \
-llibc.a \

...

# Tool invocations
i2c_ex3_external_loopback.out: $(OBJS) $(CMD_SRCS) $(LIB_SRCS) $(GEN_CMDS)
	@echo 'Building target: "$@"'
	@echo 'Invoking: C2000 Linker'
	"/Applications/ti/ccs1271/ccs/tools/compiler/ti-cgt-c2000_22.6.1.LTS/bin/cl2000" -v28 -ml -mt --cla_support=cla1 --float_support=fpu32 --tmu_support=tmu0 --vcu_support=vcu2 -Ooff --define=DEBUG --define=CPU1 --diag_suppress=10063 --diag_warning=225 --diag_wrap=off --display_error_number --abi=eabi -z -m"i2c_ex3_external_loopback.map" --heap_size=0x200 --stack_size=0x3F8 --warn_sections -i"/Applications/ti/ccs1271/ccs/tools/compiler/ti-cgt-c2000_22.6.1.LTS/lib" -i"/Applications/ti/ccs1271/ccs/tools/compiler/ti-cgt-c2000_22.6.1.LTS/include" --reread_libs --define=RAM --diag_wrap=off --display_error_number --xml_link_info="i2c_ex3_external_loopback_linkInfo.xml" --entry_point=code_start --rom_model -o "i2c_ex3_external_loopback.out" $(ORDERED_OBJS)
	@echo 'Finished building target: "$@"'
	@echo ' '

The compiler args must come before the flag to run the linker, -z, and the linker args have to come before the in files. It also shows the weird requirement to have the full name of the static libs with -llibc.a.

Before I fully commit to yes on this, I'll try building a few examples with the linker args after the in files but this family of compilers is very particular about the order of things, so I don't think it will work.

@EngJay
Copy link
Author

EngJay commented Oct 3, 2024

@jpakkane It appears including the linker args after the in files does work despite that it differs from the specification of the command format in TI's docs, so that eliminates one of three problems. Whether it is wise to depend on an undocumented format for the linking command is something to consider the ambiguous specification of the command format.

The compiler args still need to be included before -z and I reconfirmed that the static libs must be included last with the full name, so exceptions are still necessary for this compiler family but can be reduced from what is currently in my PR. I'll rework it and re-request a review.

@EngJay EngJay marked this pull request as draft October 5, 2024 14:32
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

Successfully merging this pull request may close these issues.

2 participants