Write a makefile with one rule for many targets? - python

It may seem as a very simple question, but I could not find any way to fix it.
My intention is to convert every ".ui" file into a ".py" file by invoking the pyuic4 command (from PyQt). I tried to manage this with a very short makefile:
%.py: %.ui
pyuic4 $< --output $#
That's all I need at the moment.
The makefile is named "Makefile" and located in the folder where "make" is invoked from, and so are the ".ui" files. "pyuic4(.bat)" is in the system's path (Windows 7), and so are the Unix Utilities where "make" is part of.
When running "make" from the Windows console, it says:
make: *** No targets. Stop.
Invoking pyuic4 from the command line with explicit file names works.
I know I could specify any target file by its own, but if possible I want to avoid this.
Any ideas?

As per kasterma's comment, you need to tell make which target to build, but you've only provided a pattern rule. This can be done in the following way.
UIFILES := $(wildcard *.ui)
PYFILES := $(UIFILES:.ui=.py)
.PHONY: all
all: $(PYFILES)
%.py: %.ui
pyuic4 $< --output $#

As you are obviously using a GNU Makefile syntax, I would advise you to write your rule like this:
UIFILES = $(wildcard *.ui)
.PHONY: ui2py
ui2py: $(UIFILES)
#for uifile in $(UIFILES); do \
pyuic4 $$(uifile) --output $${uifile%.ui}.py; \
done

Although the problem could be solved by either perror's or eriktous' solution, I'm now going the third way as mentioned by eriktous by simply invoking the pyuic4 command with a shell script. It's running quite fast and even if the output will result in identical files, no harm will be done for the source code control.
I encountered a second point, which may have distracted me. The pyuic4 command is really named pyuic4.bat, which is a "batch file" in Windows, similar to shell scripts in a Linux/Unix environment; similar, but not identical. If a batch file is invoked from another batch file it should be invoked with a leading "call" statement to prevent termination of the batch after the first invocation.
If I have three files (the # sign is to prevent the command from being listed during execution)
D:\Projekte\test>type main.cmd
#sub1
#sub2
D:\Projekte\test>type sub1.cmd
#echo This is sub 1
D:\Projekte\test>type sub2.cmd
#echo This is sub 2
... the result is just
D:\Projekte\test>main
This is sub 1
So my "solution" for this very small thing is a simple batch file called "update.cmd", which may be expanded by copies of this line:
call pyuic4 mainwindow.ui --output mainwindow.py
That's not what I initially wanted, but it works for me.
But anyway, thanks for your help :-)

Related

Invoking g++ via `subprocess.run` in Python causes "exec format error" in executable

Using Python 3.7, I am trying to invoke g++ to compile and build a C++ file via
#!/usr/bin/env python3
import subprocess
if __name__ == '__main__':
subprocess.run(
executable="/usr/bin/g++",
args=["/some/path/source.cpp", "-std=c++17"],
shell=True
)
When I run the script, the executable builds. I then chmod u+x it. However, when I try to execute the executable, it fails and says:
-bash: ./a.out: cannot execute binary file: Exec format error
I've read some other posts regarding this error however none are applicable. For some reason, this method fails, however when I run g++ natively in my terminal, it works as expected.
Edit: When I invoke file a.out, the output is
a.out: ELF 32-bit LSB relocatable, ARM, EABI5 version 1 (SYSV), not stripped
Appreciate any help, thanks!
The executable parameter to subprocess is only rarely needed. With shell=False, it overrides args[0] as the program to run (allowing argv[0] to be customized, as for a login shel). With shell=True (which should be avoided when possible, partly because it doesn’t do what you think with your carefully separated args list), it replaces the implicit /bin/sh invoked to run the command. The standard option to run one command is -c, so you ran
/usr/bin/g++ -c /some/path/source.cpp -std=c++17
which indeed produces a relocatable (i.e., a .o file). a.out is not the normal name for such, but perhaps it’s a fallback when the directory containing the source is not writable.

How to create Makefile in Python

I have never made a Makefile for Python before and I am struggling to figure it out. I found some sample code online and tried to apply it to my code but it is not working. If I wanted to run the program in command line I would do this: python cryptBreak.py encrypted.txt plain.txt.
Here is what I got for the Makefile so far:
PY=python2
MAIN=main
DIR=$(PWD)
.SUFFIXES: .py
FILES = \
cryptBreak.py encrypted.txt plain.txt
All:
echo " $(PY) $(DIR)/$(FILES) " \"'$$1'\" > cryptBreak
chmod 777 cryptBreak.py
You haven't explained why you need a makefile. But if you just want to have a makefile that will run the command you listed, you just have to put the command in a recipe. There's no need for all that other stuff.
all:
python cryptBreak.py encrypted.txt plain.txt
That's it. Now, in your makefile you seem to show that want to run python2, not python. If you want to do that and make a variable to hold it then you can use:
PY := python2
all:
$(PY) cryptBreak.py encrypted.txt plain.txt
If you need your makefile to do other things or have other requirements, we can't help if you don't specify them in your question.

Shell/Terminal: Execute a command for all files in a directory using their absolute path

I'm trying to execute a command for each file in a directory but while using their absolute path (such as /home/richi/mydir/myfile.py) instead of their relative path (such as myfile.py).
In other words, I want to execute a command on files in a directory based on their absolute path - similar to for file in *.py; do thecommand -a "$file"; done but not quite.
I'm asking this because I'm trying to implement a Travis CI script running in an Ubuntu 14.04 environment which will install and use pyminifier to recursively minify all the Python code files in a directory.
Please note that I'm asking may be similar to this post but it's not.
Since you're on a standard Linux distro with a full userland, you can just use the realpath command:
Print the resolved absolute file name…
For example:
$ pwd
/home/abarnert/src/test
$ touch 1
$ realpath 1
/home/abarnert/src/test/1
That's it.
If you don't know how to use that from within bash, you can call a subcommand using $(…) syntax:
$ echo $(realpath 1)
/home/abarnert/src/test/1
Of course you want to pass it the value of the variable file, but that's just as easy:
$ file=1
$ echo $(realpath "$file")
/home/abarnert/src/test/1
I'm assuming you're using bash here. With a different sh-style shell, things will be different; with tcsh or zsh or fish or something, it may be even more different.
A really old userland, or a really stripped down one (e.g., for an embedded system) might not include realpath. In that case, you can use readlink, since the GNU version, as usually, adds everything including a couple kitchen sinks, and can be used as a realpath substitute.
Or, if worst comes to worst, Python has come with a realpath function since 2.2:
$(python -c 'import os,sys; print(os.path.realpath(sys.argv[1]))' "$file")

Fortify scan for python project

Hot to generate Fortify for file for python files.
A similar question is Fortify, how to start analysis through command but it lists the steps for java.
To generate reports for python project, --python-path has to be used.
I tried following steps, but did not work.
Step 1: Clean,build
sourceanalyzer -64 -Xms1024M -Xmx10000M -b -verbose -Dcom.fortify.sca.ProjectRoot=/local/proj/9999/ -Dcom.fortify.WorkingDirectory=/local/proj/9999/working -logfile /local/proj/working/9999/working/sca.log -clean
Step 2: Scan: This step should generate fpr file
sourceanalyzer -b 9999 -verbose -Xms1024M -Xmx10000M -Dcom.fortify.sca.ProjectRoot=/local/proj/9999/ -Dcom.fortify.WorkingDirectory=/local/proj/9999/working -logfile /local/proj/9999/sca.log -python-path /path/to/python -f projec_999.fpr /local/proj/**/*.py
This did not generate any fpr file.
The second step gives the warning as:
[warning]: The -f option has no effect without the -scan option
[warning]: You may need to add some arguments to the -python-path argument to SCA.
I am not sure if I am using the correct command.
How to make sure that all python files are being scanned in the directory and subdirectories?
Is there any option to add multiple python paths?
The first step you did only does Clean, not the build step.
To perform the translation step for Python you need to specify the directories for the any Python references (-python-path) as well as the files to translate.
I am also not sure what you are doing with the ProjectRoot and WorkingDirectory, you know these are used to store temp data/intermediate files for sourceanalyzer and not the location of your source code, correct?
Something like
sourceanalyzer -b <buildId> -python-path <directories> <files to scan>'
<buildId> can be used to group different projects, you are somewhat doing this yourself when you do the ProjectRoot and WorkingDirectory (I am not sure if you need them both, can't remember and I no longer have access to test it out)
<directories> - this is where you can list out the directories that would normally be in your PythonPath environment variable (you might be able to actually call it here and save a lot of hassle). This is a comma-seperated list for Windows and a colon-seperated list for Linux
<files to scan> this is where you specify the files you want to translate/scan. You can specify individual files or use wildcard characters (* and **/* [recursive])
A sample command would look like:
sourceanalyzer -b MyApp -python-path %PYTHONPATH% ./MyApp/**/*
The other options you are putting in can be used and it would look something like this:
sourceanalyzer -b MyApp -Xms1024M -Xmx10G -logfile /local/proj/working/9999/working/sca.log -python-path %PYTHONPATH% ./MyApp/**/*
It is at this step you would check to see what files we translated from your program:
sourceanalyzer -b MyApp -show-files
Then you would perform the scan command
sourceanalyzer -b MyApp -logfile /local/proj/working/9999/working/sca.log -scan -f project.fpr
You may apply -python-path multiple times. This solves the problem which separator to use. The list of needed directories may be obtained with python:
import sys
print(sys.path)

Some subShell problems with python3

Well, I'm trying to using a python3 script to manage my aliases on my MAC OS X. At first I've put all alias commands in a single file and try to use below code to turn on/off these alias:
def enable_alias(self):
alias_controller = AliasListControl() # just a simple class to handle the single file path and other unimportant things.
os.popen('cp ~/.bash_aliases ~/.bash_aliases.bak')
os.popen('cat ' + alias_controller.path + '>> ~/.bash_aliases')
os.system('source ~/.bash_aliases')
def disable_alias(self):
os.popen('mv ~/.bash_aliases.bak ~/.bash_aliases')
os.popen('source ~/.bash_aliases')# maybe I should call some other unalias commands there
As you see, there exists an problem. When the script runs to os.system('source ~/.bash_aliases'), it will first open A subshell and execute the command, so the source operation will only take effect in the subshell, not the parent shell, then the command finished and the subshell was closed. This means what os.system('source ~/.bash_aliases') has done is just in vein.
It doesn't address your process problem, but an alternative is to put your commands either into shell scripts or into function definitions that are defined in your ~/.bash_profile.
For example, as a script:
Create the file enable_alias.sh:
filename=$1
cp ~/.bash_aliases ~/.bash_aliases.bak
# If you use `cat` here, your aliases file will keep getting longer and longer with repeated definitions... think you want to use > not >>
cp /path/to/$1.txt ~/.bash_aliases
source ~/.bash_aliases
Put this file somewhere in a folder in your PATH and make it executable. Then run it as:
enable_alias.sh A
..where your file of settings, etc is called A.txt. The $1 will pass the first value as the file name.
Or alternatively, you could do it as a function, and add that definition to your .bash_profile. (Functions can also take $1 when called.)
disable_alias(){
mv ~/.bash_aliases.bak ~/.bash_aliases
source ~/.bash_aliases
}
As you say, it might be a good idea to put unalias commands into your .bash_aliases file as well. It might also be simpler to have copies of aliases as their own files A.txt B.txt etc and just cp A.txt ~/.bash_aliases with the enable command and not use the disable command at all (disable is equivalent to enabling file B.txt, for example.)
Just some thoughts on another approach that is more 'bash-like'...
I'm not familiar with OS/X, but I am familiar with bash, so I'll take a shot at this.
First, look into Python's shutil module and/or subprocess module; os.system and os.popen are no longer the best way of doing these things.
Second, don't source a script from a subshell that's going to go away immediately afterward. Instead, add something like:
source ~/.bash_aliases
in your ~/.bashrc, so that it'll get used when every new bash is started.

Categories

Resources