VB6 [IDE](https://ja.wikipedia.org/wiki/%E7%B5%B1%E5%90%88%E9%96%8B%E7%99%BA%E7%92%B0%E5 % A2% 83) does not behave like make. In other words, a new binary file will be generated when you compile without any changes to the source code. That's fine, but each time you compile, a different binary file is generated. That is, it is indistinguishable whether the two binary files are functionally identical or have been modified. This is the first problem.
Another common configuration
\---Proj
+---Common
| CommonModule.bas
|
+---PreExe
| PreExe.vbp ←CommonModule.bas referencing
|
+---MainExe
| MainExe.vbp ←CommonModule.bas referencing
|
\---PostExe
PostExe.vbp ←CommonModule.bas not referenced
It's common to share source code at the physical file level like this. Now suppose you change a method in CommonModule.bas in the Common folder. Which one needs to be compiled because I changed it? Which one isn't necessary? You can compile everything from one end to the next, but if you compile it without needing it, a different binary will be generated even though there are no functional changes like the first problem.
Of course I think that it can be realized by using the original make command, but here I will write a program that performs vb-specific make-like behavior in Python 3 (make has been around for over 40 years, so why not put it in the VB6 development environment? Was it ...)
Refer to the VB project file (.vbp) and compile if any of the following conditions are met.
--Executable file does not exist --The project file is newer than the executable file (for example, only the version has been changed) --There is a source file newer than the executable file
Class that handles project files (.vbp)
projectfile.py
import child
import os
class ProjectFile:
__lines = []
__exe_name32 = ""
__children = []
def get_exe_name32(self):
line = [i for i in self.__lines if i.startswith("ExeName32=")]
if len(line) != 0:
(_, value) = line[0].split('=')
self.exe_name32 = value.replace('\"', '').replace('\n', '')
def get_children(self):
keys = ["Clas", "Form", "Modu"]
servived_lines = [i for i in self.__lines if i[0:4] in keys]
for line in servived_lines:
c = child.Child(line, os.path.dirname(self.fullpath))
self.__children.append(c)
@property
def exe_name32(self):
return self.__exe_name32
@exe_name32.setter
def exe_name32(self, value):
self.__exe_name32 = value
@property
def children(self):
return self.__children
def __init__(self, fullpath):
self.fullpath = fullpath
with open(fullpath, mode='r') as f:
self.__lines = f.readlines()
self.get_exe_name32()
self.get_children()
Class that handles the source files (.bas, .cls, .frm) described in the project file
child.py
import os
import datetime
class Child:
__full_path = ""
__last_write_time = ""
@property
def full_path(self):
return self.__full_path
@property
def last_write_time(self):
return self.__last_write_time
def __init__(self, line, basepath):
(_, value) = line.split('=')
if (';' in value):
(_, item) = value.split(';')
filename = item.strip()
else:
filename = value.strip()
self.__full_path = os.path.join(basepath, filename)
self.__last_write_time = os.path.getmtime(self.__full_path)
Body
vbmake.py
import projectfile
import sys
import os
import datetime
import subprocess
if __name__ == "__main__":
if (len(sys.argv) != 2):
print("vbmake.py vbpfullpath")
x = input()
exit
vbp_full_path = sys.argv[1]
vbp = projectfile.ProjectFile(vbp_full_path)
exe_full_path = os.path.join(os.path.dirname(vbp_full_path), vbp.exe_name32)
if os.path.exists(exe_full_path):
standard_time_stamp = os.path.getmtime(exe_full_path)
print(f"TimeStamp={datetime.datetime.fromtimestamp(standard_time_stamp)}")
exe_not_found = False
is_new_vbp = os.path.getmtime(vbp_full_path) > standard_time_stamp
are_new_sources = any([i.last_write_time > standard_time_stamp for i in vbp.children])
else:
exe_not_found = True
# 1)Executable does not exist
# 2)VBP file is newer than the executable file
# 3)There is a source file newer than the executable file
if exe_not_found or is_new_vbp or are_new_sources:
compiler1 = "C:\\Program Files\\Microsoft Visual Studio\\VB98\\VB6.EXE"
compiler2 = "C:\\Program Files (x86)\\Microsoft Visual Studio\\VB98\\VB6.EXE"
option = "/make"
if os.path.exists(compiler1):
compiler = compiler1
else:
compiler = compiler2
print(f"{compiler} {option} {vbp_full_path}")
subprocess.run([compiler, option, vbp_full_path])
else:
print("No compilation required")
There are two full paths of the compiler because the installation destination of VB6 is different depending on the OS and x86 / X64. It seems that compiler1 was W10 (x64) and compiler2 was W7 (x64).
I usually use a batch file
make.bat
py vbmake.py %1
I do something like this, but I found out what is called pyinstaller, so I will make it into an exe. It is great that it can be operated even in an environment without Python.
>pip install pyinstaller
do it
>pyinstaller vbmake.py
that's all. Sure enough, vbmake.exe over 10MB was generated (that's right)
Recommended Posts