ThrowTheSwitch / Ceedling

Ruby-based unit testing and build system for C projects
http://throwtheswitch.org
Other
588 stars 247 forks source link

ceedling files:assembly not available #411

Open acazzaniga opened 5 years ago

acazzaniga commented 5 years ago

CeedlingPacket.md reports it as a command to list all the assembly files, but when executed it fails with: "Don't know how to build task 'files:assembly' (See the list of available tasks with rake --tasks) Did you mean? files:test"

I'm trying to use it cause I need to add some .S file to be compiled, but they seem to be ignored in compilation.

mvandervoord commented 5 years ago

Are you using the assembly files for release or testing (or both?)

acazzaniga commented 5 years ago

Hi Mark, thanks for the answer. In the short time for testing (usage for release is not in plan now). What I'm trying to achieve is having unit tests works on our actual ARM-based device. I've already setup test_compiler, test_assembler and test_linker to use arm-none-eabi toolchain and a test_fixture for downloading code to the device through debugger and get test results from it. What I'm missing is having startup code (vector_tables, exception handlers etc.) compiled along with my tests. All of these files are .S and I could not figure out how to have ceedling call the assembler for compiling them.

mvandervoord commented 5 years ago

You've run into a bug, then. At the moment, the assembly files weren't being shown with files:assembly for tests, just releases. I'm fixing that now.

Also, if these are just support files, you may want to add them like so:

:paths:
  :test:
    - +:test/**
    - -:test/support
  :support:
    - test/support

In the example above, it will look for your test files in the test folder (and all of its subfolders, EXCEPT for the support subfolder). It will assume that your c and assembly files that are needed for testing will be in your test/support folder.

mvandervoord commented 5 years ago

Fixed the original issue. :)

acazzaniga commented 5 years ago

Thanks for fixing it. By the way, having the assembly file in the support folder did not help me in having them compiled. Is there any other flag I should switch to force it? I've already tried to add :test_build_use_assembly: TRUE in my project.yml and use TEST_FILE macro with them, but with no success.

mvandervoord commented 5 years ago

If I remember correctly, you will need to add the required files to your support list directly, so it knows it must compile and link each of them:

:files:
  :support:
    - +:/test/support/startup.c
    - +:/test/support/syscalls.s

I haven't done this with assembly files before. So I'm not 100% it works? If not, we should reopen this. :)

acazzaniga commented 5 years ago

I think we made a step forward: now it tries to compile it, but I get the following error: "ERROR: Found no file 'exception_handler.c' in search paths.", while the file provided in :files: :support: is exception_handler.S.

mvandervoord commented 5 years ago

That's what I was afraid of. I'll try to tackle that problem today. We have to enable assembly support specifically for support files, apparently. Sorry about this.

mvandervoord commented 5 years ago

I believe I have this fixed now. :)

acazzaniga commented 5 years ago

Hi Mark, I'm actually receiving the following error when using assembly file in my project "rake aborted! TypeError: no implicit conversion of nil into String" (if no assembly file is in my project.yml file everything runs fine). Can you please share the project file you used for testing? Or if you have any other idea about it (maybe it could relate to rake version or whatever)

mvandervoord commented 5 years ago

Well darn. I was hoping it was a simple fix. ;)

Here's the important part of my test setup. If yours still doesn't work, if you could post your project file (or at least the parts concerning paths), and the actual error message you're getting (it should have a traceback with line numbers and whatnot) that would be awesome.

:test_build:
  :use_assembly: TRUE

:paths:
  :test:
    - +:/test/**
    - -:/test/support
  :source:
    - src/**
  :suport:
    - test/support

:files:
  :support:
    - +:test/support/startup.s
acazzaniga commented 5 years ago

Hi Mark,

I cloned last code version from master branch and built ceedling 0.29.0.

I created a simple test project, so there is no extra complexity. This is my project.yml file

:project:
  :use_
test_preprocessor: TRUE
  :build_root: build

:test_build:
  :use_assembly: TRUE

:paths:
  :test:
    - +:test/**
    - -:test/support
  :source:
    - src/**
  :suport:
    - test/support

:files:
  :support:
    - +:test/support/exception_handler.s

This is the error I get:

rake aborted!
TypeError: no implicit conversion of nil into String
/Library/Ruby/Gems/2.3.0/gems/ceedling-0.29.0/lib/ceedling/rake_wrapper.rb:18:in `[]'
/Library/Ruby/Gems/2.3.0/gems/ceedling-0.29.0/lib/ceedling/dependinator.rb:82:in `block in enhance_test_build_object_dependencies'
/Library/Ruby/Gems/2.3.0/gems/ceedling-0.29.0/lib/ceedling/dependinator.rb:81:in `enhance_test_build_object_dependencies'
/Library/Ruby/Gems/2.3.0/gems/ceedling-0.29.0/lib/ceedling/test_invoker.rb:129:in `block in setup_and_invoke'
/Library/Ruby/Gems/2.3.0/gems/ceedling-0.29.0/lib/ceedling/test_invoker.rb:76:in `setup_and_invoke'
/Library/Ruby/Gems/2.3.0/gems/ceedling-0.29.0/lib/ceedling/tasks_tests.rake:11:in `block (2 levels) in <top (required)>'
/Library/Ruby/Gems/2.3.0/gems/ceedling-0.29.0/bin/ceedling:332:in `block in <top (required)>'
/Library/Ruby/Gems/2.3.0/gems/ceedling-0.29.0/bin/ceedling:319:in `<top (required)>'
/usr/local/bin/ceedling:22:in `load'
/usr/local/bin/ceedling:22:in `<main>'
acazzaniga commented 5 years ago

Hi @mvandervoord, in the meantime this is being fixed, I'm working on a workaround to manually compile assembly files and invoke linker to assemble all object files (both created manually and by ceedling). Is there a way to save all the .o files produced in compile step by ceedling, so I can use them in the fixture?

korigod commented 4 years ago

@mvandervoord, I'm getting TypeError: no implicit conversion of nil into String too, is there any progress on this issue?

mvandervoord commented 4 years ago

Feeling adventurous? Grab the branch improve_dependencies_plugin. I'd love to hear if this fixes your issue.

korigod commented 4 years ago

Unfortunately, it's no different. Is it possible to somehow get more meaningful error message?

mvandervoord commented 4 years ago

It already returns more than you've pasted above. Ruby returns an entire stacktrace when it has an error. It'd be good to see that. It'd also be good to know what your project.yml file looks like so I can try to reproduce it.

I'm using assembly in both tests and release, but that doesn't mean it's perfect yet. ;)

LouisHeche commented 4 years ago

@mvandervoord I also have the issue no implicit conversion of nil into String (TypeError) with ceedling version 0.30.0. Is there a fix that I've missed? Or any workaround to easily add some .asm file to the build?

Thanks

CezaryGapinski commented 4 years ago

Or any workaround to easily add some .asm file to the build?

By default ceedling use .s extension to the assembly files, so when your extension is different you should change the default extension and add something like below the project.yml:

:extension:
  :assembly: ".asm"
LanceBeasley commented 3 years ago

EDIT: I'm new to Ceedling, just realized I'm using 0.29.1. I'll update to the latest and report back.

ORIGINAL: I'm having the same problem, but in this case I'm trying to test a C-callable function written in assembly that isn't getting built.

It seems that either the assembly file is compiled, but the test runner file isn't, or the test runner is, but the assembly file gets left out.

I've tried adding/removing the .s file explicitly to the :source: section, and I can manage either to get the error that _main and start_initialization are undefined, or that get_sys_values (the assembly function I want to test) is undefined.

cosmikwolf commented 1 week ago

I am also getting an error that looks like ceedling tries to access support asm files with a .c extension instead...

I am seeing this error on the latest pre-release tag 1.0.0-f08576b f08576b

here is my config:

:extension:
  :assembly: .s

:files:
  :support:
    - +:./projects/009_pendant_application/startup_stm32h563xx.s

and the error:

🧨 EXCEPTION: Found no file `startup_stm32h563xx.c` in search paths.

Debug Backtrace ==>
ruby/3.3.5/lib/ruby/gems/3.3.0/gems/ceedling-1.0.0/lib/ceedling/file_finder_helper.rb:92:in `blow_up': (CeedlingException)
        ruby/3.3.5/lib/ruby/gems/3.3.0/gems/ceedling-1.0.0/lib/ceedling/file_finder_helper.rb:76:in `handle_missing_file'
        ruby/3.3.5/lib/ruby/gems/3.3.0/gems/ceedling-1.0.0/lib/ceedling/file_finder.rb:161:in `find_build_input_file'
        ruby/3.3.5/lib/ruby/gems/3.3.0/gems/ceedling-1.0.0/lib/ceedling/test_invoker.rb:358:in `block (3 levels) in setup_and_invoke'
        ruby/3.3.5/lib/ruby/gems/3.3.0/gems/rake-13.2.1/lib/rake/file_list.rb:79:in `each'
        ruby/3.3.5/lib/ruby/gems/3.3.0/gems/rake-13.2.1/lib/rake/file_list.rb:79:in `each'
        ruby/3.3.5/lib/ruby/gems/3.3.0/gems/ceedling-1.0.0/lib/ceedling/test_invoker.rb:357:in `block (2 levels) in setup_and_invoke'
        ruby/3.3.5/lib/ruby/gems/3.3.0/gems/ceedling-1.0.0/lib/ceedling/test_invoker.rb:356:in `each'
        ruby/3.3.5/lib/ruby/gems/3.3.0/gems/ceedling-1.0.0/lib/ceedling/test_invoker.rb:356:in `block in setup_and_invoke'
        ruby/3.3.5/lib/ruby/gems/3.3.0/gems/ceedling-1.0.0/lib/ceedling/build_batchinator.rb:26:in `build_step'
        ruby/3.3.5/lib/ruby/gems/3.3.0/gems/ceedling-1.0.0/lib/ceedling/test_invoker.rb:355:in `setup_and_invoke'
        ruby/3.3.5/lib/ruby/gems/3.3.0/gems/ceedling-1.0.0/lib/ceedling/tasks_tests.rake:25:in `block (2 levels) in <top (required)>'
        ruby/3.3.5/lib/ruby/gems/3.3.0/gems/rake-13.2.1/lib/rake/task.rb:281:in `block in execute'
        ruby/3.3.5/lib/ruby/gems/3.3.0/gems/rake-13.2.1/lib/rake/task.rb:281:in `each'
        ruby/3.3.5/lib/ruby/gems/3.3.0/gems/rake-13.2.1/lib/rake/task.rb:281:in `execute'
        ruby/3.3.5/lib/ruby/gems/3.3.0/gems/rake-13.2.1/lib/rake/task.rb:219:in `block in invoke_with_call_chain'
        ruby/3.3.5/lib/ruby/gems/3.3.0/gems/rake-13.2.1/lib/rake/task.rb:199:in `synchronize'
        ruby/3.3.5/lib/ruby/gems/3.3.0/gems/rake-13.2.1/lib/rake/task.rb:199:in `invoke_with_call_chain'
        ruby/3.3.5/lib/ruby/gems/3.3.0/gems/rake-13.2.1/lib/rake/task.rb:243:in `block in invoke_prerequisites'
        ruby/3.3.5/lib/ruby/gems/3.3.0/gems/rake-13.2.1/lib/rake/task.rb:241:in `each'
        ruby/3.3.5/lib/ruby/gems/3.3.0/gems/rake-13.2.1/lib/rake/task.rb:241:in `invoke_prerequisites'
        ruby/3.3.5/lib/ruby/gems/3.3.0/gems/rake-13.2.1/lib/rake/task.rb:218:in `block in invoke_with_call_chain'
        ruby/3.3.5/lib/ruby/gems/3.3.0/gems/rake-13.2.1/lib/rake/task.rb:199:in `synchronize'
        ruby/3.3.5/lib/ruby/gems/3.3.0/gems/rake-13.2.1/lib/rake/task.rb:199:in `invoke_with_call_chain'
        ruby/3.3.5/lib/ruby/gems/3.3.0/gems/rake-13.2.1/lib/rake/task.rb:188:in `invoke'
        ruby/3.3.5/lib/ruby/gems/3.3.0/gems/rake-13.2.1/lib/rake/application.rb:188:in `invoke_task'
        ruby/3.3.5/lib/ruby/gems/3.3.0/gems/rake-13.2.1/lib/rake/application.rb:138:in `block (2 levels) in top_level'
        ruby/3.3.5/lib/ruby/gems/3.3.0/gems/rake-13.2.1/lib/rake/application.rb:138:in `each'
        ruby/3.3.5/lib/ruby/gems/3.3.0/gems/rake-13.2.1/lib/rake/application.rb:138:in `block in top_level'
        ruby/3.3.5/lib/ruby/gems/3.3.0/gems/rake-13.2.1/lib/rake/application.rb:147:in `run_with_threads'
        ruby/3.3.5/lib/ruby/gems/3.3.0/gems/rake-13.2.1/lib/rake/application.rb:132:in `top_level'
        ruby/3.3.5/lib/ruby/gems/3.3.0/gems/ceedling-1.0.0/bin/cli_helper.rb:255:in `run_rake_tasks'
        ruby/3.3.5/lib/ruby/gems/3.3.0/gems/ceedling-1.0.0/bin/cli_handler.rb:237:in `build'
        ruby/3.3.5/lib/ruby/gems/3.3.0/gems/ceedling-1.0.0/bin/cli.rb:371:in `build'
        ruby/3.3.5/lib/ruby/gems/3.3.0/gems/thor-1.3.2/lib/thor/command.rb:28:in `run'
        ruby/3.3.5/lib/ruby/gems/3.3.0/gems/thor-1.3.2/lib/thor/invocation.rb:127:in `invoke_command'
        ruby/3.3.5/lib/ruby/gems/3.3.0/gems/thor-1.3.2/lib/thor.rb:538:in `dispatch'
        ruby/3.3.5/lib/ruby/gems/3.3.0/gems/ceedling-1.0.0/bin/cli.rb:93:in `start'
        ruby/3.3.5/lib/ruby/gems/3.3.0/gems/ceedling-1.0.0/bin/ceedling:124:in `<top (required)>'
        ruby/3.3.5/bin/ceedling:25:in `load'
        ruby/3.3.5/bin/ceedling:25:in `<main>'
🌱 Ceedling could not complete operations because of errors
cosmikwolf commented 1 week ago

Also, libraries sometimes have .s and .S files that come together (like threadx for example), and it looks like the function find_build_input_file strips the extension from the file name, and then tries to re-add using the :extension: selection. It appears that there is not support for multiple extensions here.

I think it would make a lot of sense to allow someone to put a list of extensions for filenames like so:

:extension:
  :header: .h
  :source: .c
  :assembly:
    - .s
    - .S

I opened https://github.com/ThrowTheSwitch/Ceedling/issues/947 as a feature request this is not the source of this bug though.

I tried copying the files to a support folder, and renaming them to a .s extension and they still are not picked up:

:extension:
  :assembly: .s
:paths:
  :support:
    - +:projects/009_application/test/support

this one does not yield any errors, but also skips compiling the file

cosmikwolf commented 1 week ago

I found this note in file_finder.rb

    # NOTE: We carefully add file extensions below with string addition instead of using .ext()
    #       Some legacy files can include naming conventions like <name>.##.<ext> for versioning.
    #       If we use .ext() below we'll clobber the dotted portion of the filename

I decided to validate this in irb, with ruby 3.3.0, and it seems like it behaves as expected, even with multiple periods in the file name:

irb(main):173> fw.basename("test.#232.omg.wtf.txt").ext()
=> "test.#232.omg.wtf"
irb(main):174> fw.basename("test.txt").ext()
=> "test"
irb(main):175> fw.basename("test.23.txt").ext()
=> "test.23"

it also could use extname to extract the extension, and re-add it:

irb(main):164> fw.extname("test.#232.omg.wtf.txt")
=> ".txt"
irb(main):165> fw.extname("test.txt")
=> ".txt"
irb(main):166> fw.extname("test.23.txt")
=> ".txt"
irb(main):167> fw.extname("test.#232.omg.wtf.txt")
=> ".txt"
mkarlesky commented 6 days ago

Hi, @cosmikwolf. I'm sorry this is not working for you.

There's a few things at play here. First, generally speaking, assembly support in Ceedling has been basic and piecemeal. We did some work on this in the last year, but in a quick review I see various gaps that are impacting you. Long story short, I don't think Ceedling is able to support your specific need at the moment. I suspect there were some ambiguities partially supporting assembly files as support files in earlier versions of Ceedling (alluded to in the earlier discussion for this issue). I would have to dig in more to determine exactly what is working for test builds. I think there may be both a bug at play as well as functional gaps. Adding assembly files to a release build is, to my knowledge, working.

To respond to the specific issues you've raised:

  1. If you take a look at the latest documentation for the latest Ceedling (1.0.0 prerelease) — here & here — you'll find that the support paths and support files, as currently implemented, are specific to C files. This explains why assembly files are not being found and why a C file extension is being added. Realistically, we've missed some validation that should you be telling you this.
  2. File finding generally is a big area for improvement once 1.0.0 is officially released. When Ceedling began its life it had simple project structures in mind that simplified its earliest construction. Ceedling is not great today at distinguishing files of the same name in different paths, and its file finding limitations are compounded by another early design decision to support only one file extension per file type (I'll respond to this separately in your other issue). The extension stripping you found is the fruiting of these two design limitations coming together.

Can you explain what exactly you are trying to accomplish with assembly files? From the little you've posted I gather you're trying to incorporate assembly into unit tests?

cosmikwolf commented 6 days ago

@mkarlesky thank you for your reply!

I was coming to a similar conclusion when I was trying to get it to recognize the files properly in my fork: https://github.com/cosmikwolf/Ceedling/tree/assembly_file_fix

I have not programmed in ruby for years, so I am still fighting with my linter a bit to use your linter config.

I am using threadx on an stm32h5 project and I am trying to compile to test on a qemu target, but I have deduced that it was not compiling in the exception handlers, all which are in vendor supplied .s and .S files.

as it turns out, I did not realize there was a flag to turn on and off assembly files in the config. This made it work for me:

:test_build:
  :use_assembly: TRUE
mkarlesky commented 6 days ago

@cosmikwolf Oh, wow. It did work. Great! Can you share a bit more of your config specific to this? I'd like to use a real world configuration to double check some things.