Skip to content

makefiles/utils/{strings, paths}: Add function library.#11218

Closed
jcarrano wants to merge 4 commits intoRIOT-OS:masterfrom
jcarrano:make-path-utilities
Closed

makefiles/utils/{strings, paths}: Add function library.#11218
jcarrano wants to merge 4 commits intoRIOT-OS:masterfrom
jcarrano:make-path-utilities

Conversation

@jcarrano
Copy link
Copy Markdown
Contributor

@jcarrano jcarrano commented Mar 20, 2019

Contribution description

Add a set of functions written in pure makefile. The only function that is really useful now is relpath, to calculate relative paths in systems without coreutils/realpath (e.g. Mac).

Tests were added to tests/build_system_utils. The Makefile for the test was also reworked to avoid code repetition.

Testing procedure

Run make -C tests/build_system_utils. You should see several green lines showing tests that passed.

Issues/PRs references

Needed for #10195 .

@jcarrano jcarrano added Area: build system Area: Build system Type: new feature The issue requests / The PR implemements a new feature for RIOT labels Mar 20, 2019
@jcarrano jcarrano requested a review from cladmi March 20, 2019 13:09
# default message is shown.
# Returns:
# empty string
assert_eq = $(if $(call streq,$(1),$(2)),,$(error $(if $(3),$(3),Expected "$(2)" and got "$(1)")))
Copy link
Copy Markdown
Contributor

@cladmi cladmi May 8, 2019

Choose a reason for hiding this comment

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

This one does not work as documented.

These two cases both work when they should not:

test-assert-eq:
	...
	# Test put here as `test-assert-eq_negative` does not test correctly, and the `negative` tests cannot really have multiple commands on different lines.
	@test -z "$(call assert_eq,a,a b,"This should fail")"
	@test -z "$(call assert_eq,lol%,lola,"This should fail")"

Problem is that streq is not streq. It would maybe just be better with a define so multiline using ifneq.


# Return an empty string if the arguments are different (works only for single
# words
streq = $(filter $(1),$(2))
Copy link
Copy Markdown
Contributor

@cladmi cladmi May 8, 2019

Choose a reason for hiding this comment

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

Even with only single words, it does not work. Using findstring would be better to not match patterns.
Here it should be checked that indeed words $(1) == 1 and words $(2) == 1.

# as true.

# Return a string ("x") if the argument is empty and vice versa
strnot = $(if $(1),,x)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The if is somehow clear enough and strnot is unused.

concat ?= $(if $(1),$(firstword $(1))$(call concat,$(call rest,$(1))),)

# Intercalate: concatenate words in a list with a separator between each one.
intercal = $(firstword $(2))$(call concat,$(addprefix $(1),$(call rest,$(2))))
Copy link
Copy Markdown
Contributor

@cladmi cladmi May 8, 2019

Choose a reason for hiding this comment

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

By taking the list as first argument and the separator as second, concat could be the same "public" function I think.

Concatenate a list of strings:

$1: list of strings
$2: join str, default to empty

Maybe for the implementation you still need the other one but only one public would be enough.

In that case it could use the python join or just concat in general.


define command_should_fail
$1 2>/dev/null && { echo "Command '$1' should have failed but did not" >&2; $1; exit 1; } || true
$1 2>/dev/null && { $(call fail_message,Command '$1' should have failed but did not) >&2; $1; exit 1; } || $(call ok_message,$2)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This does not work, none of the negative functions detect when something does not fail.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

With this the test still pass:

diff --git a/makefiles/utils/test-checks.mk b/makefiles/utils/test-checks.mk
index 3ee960cfd..f99a3d12e 100644
--- a/makefiles/utils/test-checks.mk
+++ b/makefiles/utils/test-checks.mk
@@ -4,7 +4,7 @@ test-ensure_value:
        @test "$@" = "$(call ensure_value,$@,"This should not fail")"

 test-ensure_value-negative:
-       @echo $(call ensure_value,$^,"This should fail")
+       true

 test-assert:
        @test -z "$(call assert,$@,"This should not fail")"

Copy link
Copy Markdown
Contributor

@cladmi cladmi left a comment

Choose a reason for hiding this comment

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

It is quite big for a single commit.

I would rather split the assert thing in its own PR.

Also the tests/build_system_utils refactoring should go alone, right now the negative tests do not correctly test when test-ensure_value-negative was testing before.

I did not look at the paths part yet.

@cladmi
Copy link
Copy Markdown
Contributor

cladmi commented May 8, 2019

Oops, my bad, I used "add comment" instead of "add to review" and even edited the old ones as thought it was in a review… 😞

@jcarrano
Copy link
Copy Markdown
Contributor Author

jcarrano commented May 9, 2019

@cladmi I stated to fix some of the stuff, but each time I approach this I cannot help feeling I'm reinventing the wheel, or in this case, recursive data types, and if I were to keep on going I'd probably end up defining folds, and zips, and maps, and a whole language on top of Make.

On the other hand, since we don't want a configure step (and we have our good reasons) we need to have quite a bit of functionality in make.

Now, looking around I see that Make with Guile (i.e. scheme) support is available in ubuntu. Writing all this complex logic in scheme is much easier. Even for someone who does not know programming (read SICP).

There's still the issue of Mac users (Windows users can run Ubuntu via WLS). AFAIK the newer versions of Make are available on mac (via homebrew).

In conclusion:

  • We should implement these functions using scheme.
  • Switch the ubuntu image from make to make-guile.
  • Mac users: if you want the build to run natively in your platform, please make a small effort and setup your system with up-to-date tools.

@cladmi
Copy link
Copy Markdown
Contributor

cladmi commented May 13, 2019

Just keep the functions we currently need that are hard to do directly in make.

Some of the utils are not explicitely needed strnot and streq are just replacing what is normally done in make with a different name.

If the new needed one is currently only relpath for thin-archives we can just first use the binary/a python version and update if there is really a performance issue.

@jcarrano jcarrano force-pushed the make-path-utilities branch from 6aa6917 to e955205 Compare August 28, 2019 16:07
jcarrano and others added 4 commits August 28, 2019 18:09
Add a set of functions written in pure makefile. The only function
that is really useful now is relpath, to calculate relative paths
in systems without coreutils/realpath (e.g. Mac).

Tests were added to tests/build_system_utils. The Makefile for the
test was also reworked to avoid code repetition.
Use the automatic rules to run the test-exported-variables, test-memoized-variables
targets.
Add functions to convert to lowercase/uppercase and another one that also
replaces dashes for underscores.

This is a remake of a PR by @cladmi (pr RIOT-OS#12119)

The Make version is about 20 times faster than using the shell. The following
patch can be used for testing (run make --no-print-directory -C examples/hello-world/ clean)

diff --git a/examples/hello-world/Makefile b/examples/hello-world/Makefile
index 258d8e9..1f2adf837 100644
--- a/examples/hello-world/Makefile
+++ b/examples/hello-world/Makefile
@@ -16,3 +16,5 @@ DEVELHELP ?= 1
 QUIET ?= 1

 include $(RIOTBASE)/Makefile.include
+
+include $(RIOTMAKE)/utils/strings.mk
diff --git a/makefiles/utils/strings.mk b/makefiles/utils/strings.mk
index c571cd6..7dce7d80d 100644
--- a/makefiles/utils/strings.mk
+++ b/makefiles/utils/strings.mk
@@ -39,3 +39,28 @@ lowercase = $(call xlate,$(_UPPER_LETTERS),$(_LOWER_LETTERS),$(1))
 uppercase = $(call xlate,$(_LOWER_LETTERS),$(_UPPER_LETTERS),$(1))

 uppercase_and_underscore = $(call uppercase,$(subst -,_,$1))
+
+
+#~ # Local testing
+#~ var = abcdefghijklmnopqrstuvwxyz-123456789
+#~ VAR = ABCDEFGHIJKLMNOPQRSTUVWXYZ_123456789
+
+#~ ifneq ($(call uppercase_and_underscore,$(var)),$(VAR))
+  #~ $(error $(call uppercase_and_underscore,$(var)))
+#~ endif
+
+#~ NUM ?= 10000
+#~ iters := $(shell seq $(NUM))
+
+#~ d_0 := $(shell date +%s.%N)
+#~ a := $(foreach i,$(iters),$(call uppercase_and_underscore,$(var)))
+#~ d_end := $(shell date +%s.%N)
+#~ d_diff := $(shell echo $(d_end) - $(d_0) | bc)
+#~ $(warning makefile $(d_diff): $(d_0) - $(d_end))
+
+#~ d_0 := $(shell date +%s.%N)
+#~ $(foreach i,$(iters),$(shell echo $(var)| tr 'a-z-' 'A-Z_'>/dev/null))
+#~ d_end := $(shell date +%s.%N)
+
+#~ d_diff := $(shell echo $(d_end) - $(d_0) | bc)
+#~ $(warning shell    $(d_diff): $(d_0) - $(d_end))
The rest function gets the "tail" of a list and is often used to define
recursive list processing functions.

It uses make's wordlist function which requires an upper bound, which was
being computed using the "words" function. Replacing this by a very high
number (2**31 - 1) makes it much faster and will never be an issue (the
build machine will probably run out of memory before).

Note that GNU Make does not like values larger than 2**31.
@jcarrano
Copy link
Copy Markdown
Contributor Author

@cladmi regardless of the fate of the string library, do you think the changes to the build_system_utils Makefile make sense? I like that with this patch it shows which tests are being run.

@cladmi
Copy link
Copy Markdown
Contributor

cladmi commented Sep 12, 2019

The negative test does not detect errors as said in #11218 (comment)

make -C tests/build_system_utils/
make: Entering directory '/home/harter/work/git/RIOT/tests/build_system_utils'
Building application "tests_build_system_utils" for "native" with MCU "native".

"make" -C /home/harter/work/git/RIOT/boards/native
"make" -C /home/harter/work/git/RIOT/boards/native/drivers
"make" -C /home/harter/work/git/RIOT/core
"make" -C /home/harter/work/git/RIOT/cpu/native
"make" -C /home/harter/work/git/RIOT/cpu/native/periph
"make" -C /home/harter/work/git/RIOT/cpu/native/vfs
"make" -C /home/harter/work/git/RIOT/drivers
"make" -C /home/harter/work/git/RIOT/drivers/periph_common
"make" -C /home/harter/work/git/RIOT/sys
"make" -C /home/harter/work/git/RIOT/sys/auto_init
   text	   data	    bss	    dec	    hex	filename
  22798	    568	  47652	  71018	  1156a	/home/harter/work/git/RIOT/tests/build_system_utils/bin/native/tests_build_system_utils.elf
 [OK] ensure_value 
 [OK] assert 
 [OK] assert_not 
 [OK] ensure_value (negative) 
 [OK] assert (negative) 
 [OK] assert_not (negative) 
 [OK] exported-variables 
 [OK] memoized-variables 
 [OK] streq 
 [OK] assert_eq 
 [OK] assert_eq (negative) 
 [OK] strnot 
 [OK] rest 
 [OK] concat 
 [OK] intercal 
 [OK] lowercase 
 [OK] uppercase 
 [OK] uppercase_and_underscore 
 [OK] relpath 
 [OK] relpath-against-sys 

Having a better visual output is indeed good, if it was working.
I do not care about the color.

@stale
Copy link
Copy Markdown

stale bot commented Mar 15, 2020

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. If you want me to ignore this issue, please mark it with the "State: don't stale" label. Thank you for your contributions.

@stale stale bot added the State: stale State: The issue / PR has no activity for >185 days label Mar 15, 2020
@stale stale bot closed this Apr 15, 2020
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 State: stale State: The issue / PR has no activity for >185 days Type: new feature The issue requests / The PR implemements a new feature for RIOT

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants