Skip to content

make: add blob utility header#11870

Merged
bergzand merged 3 commits intoRIOT-OS:masterfrom
kaspar030:blobs
Nov 18, 2019
Merged

make: add blob utility header#11870
bergzand merged 3 commits intoRIOT-OS:masterfrom
kaspar030:blobs

Conversation

@kaspar030
Copy link
Contributor

@kaspar030 kaspar030 commented Jul 19, 2019

Contribution description

This PR adds a utility makefile that allows arbitrary files to be made available as headers.
This is supposed to be used with, e.g., lua, jerryscript, micropython for scripting language source files.

Testing procedure

Contains a test application. Check CI output.

Also, try changing the blobs and see if everything gets rebuilt correctly. Hammer this using make -j ....
Do the same with BUILD_IN_DOCKER=1.

Issues/PRs references

Simpler alternative to #11497.

@kaspar030 kaspar030 added Area: build system Area: Build system CI: ready for build If set, CI server will compile all applications for all available boards for the labeled PR CI: run tests If set, CI server will run tests on hardware for the labeled PR labels Jul 19, 2019
@kaspar030 kaspar030 requested review from miri64 and smlng July 19, 2019 10:42
@kaspar030 kaspar030 mentioned this pull request Jul 19, 2019
1 task
@kaspar030 kaspar030 added CI: ready for build If set, CI server will compile all applications for all available boards for the labeled PR and removed CI: ready for build If set, CI server will compile all applications for all available boards for the labeled PR CI: run tests If set, CI server will run tests on hardware for the labeled PR labels Aug 15, 2019
@emmanuelsearch
Copy link
Member

@smlng ping ;)

@kaspar030
Copy link
Contributor Author

To provide context vs #11497, this PR unifies current blob handling (which is duplicated in examples/javascript, examples/lua_REPL and examples/lua_basic, and one more coming in #2968) to a shared makefile. It is still using xxd & sed, which #11497 tries to replace with a custom make-based implementation.

IMO, while I disagree with handling this using make itself, even should we agree on that, this PR provides a clean entry-point to do that. Thus the guts of #11497 could be hooked in easily by replacing the one xxd+sed line of this PR. But that should be a different discussion.


BLOBS += blobtest.txt

TEST_ON_CI_WHITELIST += all
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not needed anymore, right ?!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yup, removed

@kaspar030
Copy link
Contributor Author

@aabadie I accidentally over-force-pushed and then re-applied your suggestion commit.

DIRS += $(RIOTCPU)/$(CPU) $(RIOTBOARD)/$(BOARD)
DIRS += $(RIOTBASE)/core $(RIOTBASE)/drivers $(RIOTBASE)/sys

BLOBS = $(APPLICATION_BLOBS)
Copy link
Contributor

@aabadie aabadie Sep 10, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not move this line to makefiles/blob.inc.mk ? Since this file is also included by Makefile.base, it will be more consistent to handle this in the related file. This is untested so maybe this doesn't work because I'm missing something.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If that line would be in blob.inc.mk, it would be used in every recursive make call (e.g., for every module). We only want it to be used for the application module. All other modules can directly use BLOBS.

From the corresponding commit description:


@kaspar030
make: pass BLOBS to makefiles/application.inc.mk

For regular modules, adding files to BLOBS is sufficient to create the
corresponding headers.

Application modules are different, as they use a minimal makefile
(makefiles.application.inc.mk) to build, thus application level
variables are not available.

This commit makes Makefile.include pass BLOBS to the application
Makefile as APPLICATION_BLOBS, and application.inc.mk use that variable
as value for BLOBS.

The indirection is necessary so submakefiles (e.g., those visited by
DIRS) do not hard override BLOBS.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it possible to add a comment about that here instead of inside the commit message ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now it is here, is that sufficient?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've added some doc to applications.inc.mk.

@kaspar030 kaspar030 added CI: ready for build If set, CI server will compile all applications for all available boards for the labeled PR and removed CI: ready for build If set, CI server will compile all applications for all available boards for the labeled PR labels Sep 10, 2019
@aabadie
Copy link
Contributor

aabadie commented Sep 11, 2019

I was asked to have a look at this PR but I don't feel confident enough to give a valuable review on the Makefile changes. Especially because they touch Makefile.base. Maybe @cladmi or @jcarrano could be of more help here ?

I have more general comments btw:
From the commit message linked above:

For regular modules, adding files to BLOBS is sufficient to create the
corresponding headers.

So this means that this PR allows to embed blob defined in modules. The problem is that the test application doesn't show this. It's only applied to application blobs.

Another aspect is that the current implementation only generates a header from a text file and include this to the build. Conceptually, this is not really a blob.

@jcarrano
Copy link
Contributor

I'll summarize a discussion we had AFK with @emmanuelsearch. Sorry for the long comment, and I don't mean to bash this PR- I feel that many of the ideas expressed here apply equally to other instances where we may be wanting to "abstract away" common functionality.

All this would achieve is remove the need for the following snippet to exist in the application's makefile:

JS_PATH = $(BINDIR)/js/$(MODULE)

# add directory of generated *.js.h files to include path
CFLAGS += -I$(JS_PATH)

# generate .js.h header files of .js files
JS = $(wildcard *.js)
JS_H = $(JS:%.js=$(JS_PATH)/%.js.h)

BUILDDEPS += $(JS_H) $(JS_PATH)/

include $(RIOTBASE)/Makefile.include

$(JS_PATH)/:
	$(Q)mkdir -p $@

$(JS_H): $(JS_PATH)/%.js.h: %.js | $(JS_PATH)/
	$(Q)xxd -i $< | sed 's/^unsigned/const unsigned/g' > $@

That was taken from the jerryscript package. Lua has something similar. Note that header files will end up in a js-specific path.

The propose module removes the need for this code, at the price of:

  • Reduced flexibility.
    • User cannot have different paths for different file types.
    • The datatype (const unsigned) is fixed.
      • In fact, the whole output template is fixed.
  • The code is now "officially" part of the RIOT build system, which means people will depend on in and each change is an API change.

The reduced flexibility means that any deviation from the assumption that this new module does would require reverting back to the above snippet.

Now, there are some very real problems which are not being solved by this or by anything currently in use. Many of these are actually limitations of our build system, unrelated to this PR.

  • Making files into arrays is easy, but the interesting part is indexing them (i.e. putting them into some sort of structure or table)
    • I have come to believe that this is best done in an application specific way.
  • We still have to come up with a way to generate just the required dependencies.
    • $(OBJC) $(OBJCXX): $(BLOB_H) (or builddeps...) is overkill, but we currently know no better way
  • What if I want to generate an object instead of a header.
    • Needed, for example, to properly integrate stuff like vendor supplied binaries/ bootloaders /etc.
    • Compiling a generated C file and is tricky.
    • makefiles/blobs: Add rules for binary blob embedding.  #11497 does that, but I did not insist too much on that because the rest of the complaints in this PR apply to it as well (my justification for that PR was that it is something tricky to get right).

In conclusion, I'm against too much convenience functions, since these have to be maintained too.

@kaspar030
Copy link
Contributor Author

kaspar030 commented Sep 13, 2019

  • User cannot have different paths for different file types.

If there's a use-case for that, it can be added. (e.g., by properly dealing with subfolders so blobs don't have to be in the module's folder.)

  • The datatype (const unsigned) is fixed.

Did you encounter this use case before?
Anyhow, this would be easy to add, maybe using BLOBS_VAR in addition to BLOBS.

  • In fact, the whole output template is fixed.
    I have come to believe that this is best done in an application specific way.

I agree.

  • What if I want to generate an object instead of a header.

Well, linking an object is a different function than creating data that is accessible from C from a binary.

@kaspar030
Copy link
Contributor Author

If there's a use-case for that, it can be added.

Well, I did, now BLOBS += $(wildcard js/*.js) should work correctly.

@kaspar030
Copy link
Contributor Author

So this means that this PR allows to embed blob defined in modules. The problem is that the test application doesn't show this. It's only applied to application blobs.

  • added a module using a blob

Another aspect is that the current implementation only generates a header from a text file and include this to the build. Conceptually, this is not really a blob.

  • added a binary blob

@@ -0,0 +1,2 @@
BLOBS += blobtest.bin
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This file is missing ;)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks! It was blanked out by .gitignore...

@kaspar030
Copy link
Contributor Author

  • added some possible testing methods

@emmanuelsearch
Copy link
Member

and @cladmi are you actually planning to review?

@aabadie
Copy link
Contributor

aabadie commented Oct 4, 2019

@kaspar030, do you think it's possible to achieve the same result without using SECONDEXPANSION ?
In the current state, all targets defined after are impacted, even the ones that comes after the include of blob.inc.mk in Makefile.base. This means for all those targets we'll have to be very careful not escaping them.
@cladmi, do you think you'll have time to do a proper review and also give your feedback soon ?

@bergzand
Copy link
Member

bergzand commented Oct 7, 2019

@bergzand so is that an ACK for real now ? ;)

Seeing the concerns raised by @cladmi, I'm no longer sure. I'm not confident enough in my makefile skills to merge this right before the hard freeze. Are there any issues with merging this after the hard freeze?


# make C and C++ objects of this module depend on generated headers, so they
# get re-build on changes to the blob files.
$(OBJC) $(OBJCXX): $(BLOB_H)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment is wrong, rebuilding would be done automatically from the .d generated files as the compilation is done with -MD -MP.
This also does not account for deleted files that the .d does.

This is only currently required to have the headers generated before compiling the C files, so with a : |$(BLOB_H) it would work too.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've updated the comment.

Using : |$(BLOB_H), no rebuild is triggered when changing a blob.

@cladmi
Copy link
Contributor

cladmi commented Oct 7, 2019

It looks like the SECONDEXPANSION is only required to allow having subdirectories for headers inside blob. Is this a required feature?

If it really is, the SECONDEXPANSION is not really required here.
The $$(@D) handling is only needed if the targets list is unknown to have a generic handling or pattern rules.

Here as all targets are basically known and could be handled with a stupid handling that all targets depend on having created all the directories first:

BLOB_DIRECTORIES = $(addsuffix .,$(dir $(BLOB_H)))

$(BLOB_H): $(BLOB_HDR_DIR)/%.h: % $(BLOBS) | $(BLOB_DIRECTORIES)

Or if you want one to one mapping:

set_dir_dependency = $(foreach target,$(1),$(eval $1: | $(dir $(target)).))
$(call set_dir_dependency,$(BLOB_H))

IIRC, the /. syntax is to handle make <4 as currently used in OSx.
It should not be necessary anymore after 2020.01 as make <4 is deprecated in RIOT.

For the naming, I would not say it generates blobs as #11497 did, it is an xxd wrapper than only gives read only outputs.
From what I get this is only to replace:

$(JS_H): $(JS_PATH)/%.js.h: %.js | $(JS_PATH)/
$(Q)xxd -i $< | sed 's/^unsigned/const unsigned/g' > $@

Adding directory variables creation is something that would be great globally in Makefile.base and Makefile.include added on its own instead of added here in the middle of another things that does not really need it.

$(BLOB_HDR_DIR)/.:
@mkdir -p $@

$(BLOB_HDR_DIR)%/.:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not just %/.: it is a directory creation rule ?
Is it because of some make versions? I know some have issues with implicit rules sometime.

This also apply for the .PRECIOUS line.

The directory creation rule could also be put in common in Makefile.base instead of here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It could, but as is it is self-contained.


XXD ?= xxd

$(BLOB_H): $(BLOB_HDR_DIR)/.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why this line?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not needed, I removed it.

@kaspar030
Copy link
Contributor Author

It looks like the SECONDEXPANSION is only required to allow having subdirectories for headers inside blob. Is this a required feature?

It was asked for, and it makes sense, as e.g. jerryscript uses a "js/" subfolder.

@kaspar030
Copy link
Contributor Author

If it really is, the SECONDEXPANSION is not really required here.

Does it hurt?

@kaspar030
Copy link
Contributor Author

IIRC, the /. syntax is to handle make <4 as currently used in OSx.

correct.

@kaspar030
Copy link
Contributor Author

Does it hurt?

@cladmi, other than issues with variables containing dollarsigns, do you know any downsides of enabling SECONDEXPANSION globally?

@kaspar030
Copy link
Contributor Author

@aabadie
Copy link
Contributor

aabadie commented Nov 18, 2019

#12708, please rebase.

@kaspar030
Copy link
Contributor Author

  • rebased

Copy link
Contributor

@aabadie aabadie left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just minor remaining things in the test. Otherwise that looks good. You can squash directly.

@@ -0,0 +1,10 @@
DEVELHELP ?= 0
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why disabling DEVELHELP by default? I would keep it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yup, removed the line (default is 1)



if __name__ == "__main__":
sys.exit(run(testfunc, timeout=120))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think the custom timeout is required. The test is running fast enough.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

removed the timeout

For regular modules, adding files to BLOBS is sufficient to create the
corresponding headers.

Application modules are different, as they use a minimal makefile
(makefiles.application.inc.mk) to build, thus application level
variables are not available.

This commit makes Makefile.include pass BLOBS to the application
Makefile as APPLICATION_BLOBS, and application.inc.mk use that variable
as value for BLOBS.

The indirection is necessary so submakefiles (e.g., those visited by
DIRS) do not hard override BLOBS.
Copy link
Contributor

@aabadie aabadie left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ACK!

@aabadie
Copy link
Contributor

aabadie commented Nov 18, 2019

@bergzand, we need your approval here. Are your concerns addressed ?

Copy link
Member

@bergzand bergzand left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ack

@bergzand bergzand merged commit 76b9642 into RIOT-OS:master Nov 18, 2019
@bergzand
Copy link
Member

@bergzand, we need your approval here. Are your concerns addressed ?

Yes

@kaspar030
Copy link
Contributor Author

Thanks everyone!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Area: build system Area: Build system CI: ready for build If set, CI server will compile all applications for all available boards for the labeled PR Reviewed: 1-fundamentals The fundamentals of the PR were reviewed according to the maintainer guidelines Reviewed: 2-code-design The code design of the PR was reviewed according to the maintainer guidelines Reviewed: 3-testing The PR was tested according to the maintainer guidelines Reviewed: 4-code-style The adherence to coding conventions by the PR were reviewed according to the maintainer guidelines Reviewed: 5-documentation The documentation details of the PR were reviewed according to the maintainer guidelines

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants