Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
We don’t allow questions seeking recommendations for books, tools, software libraries, and more. You can edit the question so it can be answered with facts and citations.
Closed 2 years ago.
Improve this question
I know there are many linters for programming languages, like pep8 for python, but I have never come across one for a makefile. Are there any such linters for makefiles?
Any other ways to programmatically detect errors or problems in makefiles without actually running them?
As I have grown into using a makefile, it keeps on getting more complicated and long, and for me it would make sense to have a linter to keep the makefile more readable.
Things have apparently changed. I found the following:
Checkmake
Mint
Of the two, Checkmake has (as of 2018/11) more recent development, but I haven't tried either.
I also do not know where to find make file lint (web search for "make file lint" got me here), but here is a incomplete list of shallow idea fragments for implementing a make file lint utility...
White spaces are one aspect of the readability, as tabs and spaces have distinct semantics within make file. Emacs makefile-mode by default warns you of "suspicious" lines when you try to save make file with badly spaced tabs. Maybe it would be feasible to run emacs in batch mode and invoke the parsing and verification functions from that mode. If somebody were to start implementing such a make file lint utility, the emacs lisp mode could be an interesting to check.
About checking for correctness, #Mark Galeck in his answer already mentioned --warn-undefined-variables. The problem is that there is a lot of output from undefined but standardized variables. To improve on this idea, a simple wrapper could be added to filter out messages about those variables so that the real typos would be spotted. In this case make could be run with option --just-print (aka -n or --dry-run) so as to not run the actual commands to build the targets.
It is not good idea to perform any changes when make is run with --just-print option. It would be useful to grep for $(shell ...) function calls and try to do ensure nothing is changed from within them. First iteration of what we could check for: $(shell pwd) and some other common non-destructive uses are okay, anything else should invoke a warning for manual check.
We could grep for $ not followed by ( (maybe something like [$][^$(][[:space:]] expressed with POSIX regular expressions) to catch cases like $VARIABLE which parses as $(V)ARIABLE and is possibly not what the author intended and also is not good style.
The problem with make files is that they are so complex with all the nested constructs like $(shell), $(call), $(eval) and rule evaluations; the results can change from input from environment or command line or calling make invocations; also there are many implicit rules or other definitions that make any deeper semantic analysis problematic. I think all-compassing make lint utility is not feasible (except perhaps built-in within make utility itself), but certain codified guidelines and heuristic checks would already prove useful indeed.
The only thing resembling lint behaviour is the command-line option --warn-undefined-variables.
Related
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 2 years ago.
Improve this question
I found they are all configuration file for compiling in MCU, but when and where to use which?
A script is an interpreted computer program. That is, a program that can be executed by another program (an executable called an interpreter) without first being translated into another language. A script written in a particular language needs an interpreter that understands that language.
A makefile is a script. It is interpreted by some version of Make. The language of makefiles is designed to be used in build systems, invoking shell commands to build files out of other files. It can do other things, but generally not as easily as other languages that are more general or designed with those things in mind.
Where and when to use which tool is a very broad question. Broadly speaking, Make is a good tool for building files from other files, and keeping them up to date. Other languages may be better for other purposes, such as computation, stream editing or regular expression handling.
Beta's answer is perfect. Just to give a glimpse of make, a good analogy could be a chef. When asked to cook a meal (the goal) it reads a cookbook (the makefile), identifies the ingredients (files), the proper order of operations and their description.
An important aspect of make is that it compares last modification times of files to decide whether a specific file is up-to-date or shall be rebuilt. A typical makefile contains a series of rules (which order usually does not matter) like this:
target_file: prerequisite_file_1 prerequisite_file_2 ...
recipe_line_1
recipe_line_2
...
(where each recipe line starts with a tab). This part tells make that target_file depends on prerequisite_file_1, prerequisite_file_2... That is, if target_file is needed to accomplish the goal, make will first decide whether it must be rebuilt or not:
If it does not exist make will of course try to build it.
If it exists already make will compare its last modification time with that of the prerequisite files. If target_file is older than one of the prerequisites, make will try to rebuild it.
If target_file must be rebuilt make will pass each recipe line to the shell (separate shells) which execution is supposed to build it (but make has no way to check this, it is your responsibility to write sound recipes).
Note that all this is recursive: if a prerequisite file is missing make will search for another rule that builds it. And if a prerequisite file exists but a rule also exists for which it is the target, make will check that it is up-to-date before building target_file. And it will first build missing or outdated prerequisite files before the top-level target file.
It is a bit like if the recipe in the cookbook was referring to a composite ingredient (let's say a sauce) that has its own separate recipe in the same cookbook.
The main differences with a naive shell script that would also describe the build process of a project is thus that the shell script would probably always rebuild everything while make will rebuild only what needs to be. Bonus: most make implementations are also capable of parallelisation: knowing what depends on what make can also discover what must be serialized and what could be done in parallel. On a multi-core computer, for large projects, the speed-up factor can be significant.
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 8 years ago.
Improve this question
The other day I answered a question where it was necessary to loop through all the sub-dictionaries in a given directory.
As a self-taught bash user I quickly answered the question. However, in my answer I used for DIR in $(find ...); do "something"; done to loop through the sub-directories. A polite bash guru pointed out that if I continue with bad habits like that will one day find myself in a lot of trouble.
While correcting my answer I found that I had (embarrassingly) many more bad habits. I could not find any topic like this on stackoverflow, but I am sure there are many people like me at a "beginner(++)" level with bad habits based on methods that "sort-of-works".
My question is generic albeit simple:
What are important/damaging pitfalls to avoid for someone who is using bash? (If you find the question to generic to answer I would appreciate a short description of the case with link to documentation or another SO question regarding the subject is appreciated.)
E.g. When performing loops to edit files/dirs, using globb characters, pipes, logicals, short hand notation (i.e. ``) and last but not least applying functions for purposes which they should not be used.
I found Google's Styleguide very instructive. I changed some old habits after reading it, and it has a lot of examples.
EDIT: Some points to watch beneath.
Working with variables: set value without $ and access with $
Avoid confusion by using ${..} when using the variable
Calling a command within your commandline with $()
The old syntax `` will work but you can make easy mistakes.
Avoid arrays
You normally do not really need them and they have a more difficult syntax
Start (first line) your script with #!/bin/bash
It will check and use bash when available and give an error when it is missing.
Learn regex
sed can become your close friend. Even when you only use -e 's/.../.../g'
Also other utilities use regex.
Use the case statement when checking against different possible values
Avoid too much if-then-else nesting
Do not skip the if keyword when testing with [[ .. ]]
The if statement is obsolete but easier to read
Do not use eval
When you finally understand the syntax you wil learn it is dangereous.
Shell builtin's are faster but more difficult to read
basename is a simple utility but slower than ${fullfile##*/}
Maybe you should store a note with some handy builtins somewhere.
Downwards compatible?
When you think your scripts might have to be migrated to Solaris/AIX with ksh someday, try avoiding bash-specific syntax and Linux utilities. That would be quite difficult (the -i flag in sed, additional options in find) so getting bash installed on Solaris/AIX might be a better way.
Question: E.g. When performing loops to edit files/dirs, using globb characters, pipes, logicals, short hand notation (i.e. ``) and last but not least applying functions for purposes which they should not be used.
When you have a lot of scripts using the same functions, store the functions in a file like common.h
Include this file with . common.h
Learn the difference between function xxx {..} and xxx() {..}
Use local var's and return values by stdout or the returnvalue
GNU Make under MinGW is known to be very slow under certain conditions due to how it executes implicit rules and how Windows exposes file information (per "MinGW “make” starts very slowly").
That previous question and all other resources on the issue that I've found on the internet suggest working around the problem by disabling implicit rules entirely with the -r flag. But is there another way?
I have a "portable" Makefile that relies on them, and I'd like to make it so that it does not take around a minute to start it up each time, rather than having to get the Makefile owner to alter it just for me.
You should use make -d to see all the things make is doing and try to see where the time is going. One common reason for lengthy make times are match-anything rules which are used to determine whether or not a makefile needs to be rebuilt. Most of the match-anything rules CAN be removed; they're rarely needed anymore.
You can add this to your makefile and see if it helps:
%:: %,v
%:: RCS/%,v
%:: RCS/%
%:: s.%
%:: SCCS/s.%
And, if you don't need to auto-create your makefile you can add:
Makefile: ;
(also put any included makefiles there that you don't need to auto-create).
ETA
It seems your real question can be summed up as, "why does make take so much longer to start on Windows than on Linux, and what can I do to fix that without changing makefiles?"
The answer is, nothing. Make does exactly the same amount of work on both Windows and Linux: there are no extra rules or procedures happening on Windows that could be removed. The problem is that Windows NTFS is slower than typical Linux filesystems for these lookups. I know of no system setting, etc. that will fix this problem. Your only choice is to get make to do less work so that it's faster, and the only way to do that is by removing built-in rules you don't need.
If the problem is you really don't want to edit the actual makefiles, that's simple enough to solve: just write the rules above into a small separate makefile, maybe something like speedup.mk, then set the environment variable MAKEFILES=speedup.mk before invoking make. Make will parse that makefile as well without you having to change any makefiles.
Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
Questions asking us to recommend or find a tool, library or favorite off-site resource are off-topic for Stack Overflow as they tend to attract opinionated answers and spam. Instead, describe the problem and what has been done so far to solve it.
Closed 9 years ago.
Improve this question
I want to do some refactoring of code, especially the "include"-like relationships between files. There are quite a few of them, and to get started, it would be helpful to have a list, diagram, or even a columnar graph, so that I can see at a glance what is included from where.
(In many cases, a given file is included by multiple other files, so the graph would be a DAG, not a tree. There are no cycles.)
I'm working with TeX (actually ConTeXt), but the question would seem to apply to any programming languages that has a facility like that of #include in C.
The obvious, easy answer is to do a grep or "Find in Files" on all the .tex files for the relevant keywords (\usemodule, \input, and a couple of other macros we've defined). This is better than nothing, but the output is long, and it's still difficult to see patterns in what includes what. For example, is file A usually included before file B? Is file C ever included multiple times by the same file?
I guess that brings out an additional, but optional feature: that such a tool would be able to show the sequence of includes from a particular file. So in that case the DAG could be a multigraph, i.e. there could be multiple arcs from one file to another.
Ideally, it would be nice to be able to annotate each file, giving a very brief summary of what's in it. This would form part of the text on the graph node for that file.
Probably this sort of thing could be done with a script that generates graphviz dot language. But I wanted to know if it has already been done, rather than reinvent the wheel.
As it is friday in my country right now, and I'm waiting for my colleagues to go to have a beer, I thought I'd do a little programming.
Here http://www.luki.webzdarma.cz/up/IncludeGraph.zip you can download source of a really simple utility that looks for all files in one folder, parses #includes and generates a .dot file for that.
It supports and correctly handles relative paths, and works on windows and should work on linux as well. It is written in very spartan way. My version of dot is not parsing the generated files, there is some bug, but I really need to go drinking now, see if you can fix it. I'm not a regular dot user and I dont see it, though I'm sure it is pretty obvious.
Enjoy ...
PS - If you run into trouble compiling and/or running, please let me know. Thanks.
EDIT
Ok, my bad, there was a few glitches on linux. The dot problem was it was using "graph" instead of "digraph". But it is working like charm now. Here is the link. Just type make, and if that goes, make test should generate the following diagram of the program itself:
It ignores preprocessor directives in the C++ files so it is not very useful for that directly (could be fixed by simply calling g++ with preprocessor output flag and processing that instead of the actual files). I didn't get to regexp today, but if you have any programming experience, you will find that modifying DotGraph.cpp shouldn't be very hard to hard-code your inclusion token, and to change list of file extensions. Might get to regexp tomorrow or something.
A clever and general solution would be to trace the build system (using something like strace, LD_PRELOAD, patching the binaries, or some other debugging facility).
Once you'd collected the sequence of file open/close operations, you'd just have to filter out the uninteresting stuff, it should be easy to build the dependency tree for any language as long as the following assumptions are true:
The build system will open each file when it is included.
The build system will close each file when it reaches its end.
Unfortunately, a well-written or poorly-written compiler might violate these assumptions by for instance only opening a file the first time it is included, or never closing any files.
Perhaps because of these limitations, I'm not aware of any implementation of this idea.
On the other hand, clever build systems may include functionality to compute or extract dependencies themselves. gcc has the -M option to output dependencies, and javac figures out dependencies on its own (although I don't know how to get it to output them).
As far as TeX goes, I don't know enough TeX to actually implement this, but conceptually it seems like it should be possible to redefine the low-level include to command to:
write a log of what is about to be included
call the original include command to include it
write a log of what was included
You could then build your tree from the log output.
Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 8 years ago.
Improve this question
Greetings to my revered experts!
I'm writing a command line tool(similar to ls or cat or uname etc) and I was wondering if there's a best-practice to order the arguments in the usage statement.
I'm confused because, ls's usage statement prints arguments in alphabetical order, where as cat's usage statement does not!
Try cat --help and ls --help.
Can you refer me to some documentation too, if there is a standard?
Ha, standard! No, certainly nothing like that. Pick your favorite, whichever looks nice and is organized well and is on everyone's computer already, and mimic it.
My opinions follow:
I don't see any value in alphabetical.
Order it logically, arranged into categories and put useful stuff first.
Make sure the parsing engine is solid and "standard", preferably using someone else's. Boost's Program Options or Python's optparse are good if they're in the right language for you. Most other languages have some too.
Make sure to include many examples that span the gamut of use.
No standard so to speak but they should probably be grouped by usage patterns which is how most people would use them (not alphabetically).
As with all documentation and technical writing, you first have to decide on your audience.
For example, when you want to figure out how to get sort to ignore case, you rarely know already that it's -f (fold case, who the hell thought of that?). The most useful output would have a section on data transformation options (e.g., ignore case, treat accented characters as unaccented), another on key selection (e.g., which fields or sub-fields), another of key comparisons (e.g., alpha, numeric, collation) and so on.
In any case, the sort of person who already knows it's the -f option will also know how to use less to search for that option without having to page through reams of unneeded information:-)
In fact, I'd go one better. Have two possible outputs. Make the default a usage-based format but, at the top of that, make the first usage a way of getting an alphabetical listing:
pax> paxprog --help
paxprog - truly an amazing program.
paxprog is capable of doing anything you want.
Help output options:
--help
Usage-based assistance (default).
--alpha-help
All options in alphabetical order.
Coffee-making options:
--temp=chilled|tepid|hot|damnhot
Selects the temperature.
Blah, blah, blah ...
There most certainly is a standard: http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap12.html. Note paragraph 3: "Options are usually listed in alphabetical order unless this would make the utility description more confusing. "
There's no standard, although there are some general conventions, which, I assume, you're already familiar with. It's not 100% though.