contrib: fxc2: use a fxc script to call fxc2

So any call to fxc will use our tool, as long as fxc is in the PATH.

We can also handle the option format in the script.
This commit is contained in:
Steve Lhomme 2024-04-19 08:21:10 +02:00
parent d04d70fb20
commit a8493d31f5
3 changed files with 158 additions and 262 deletions

View File

@ -1,261 +0,0 @@
From 7c502bc09182958fa7268bfa792a338891c3df7b Mon Sep 17 00:00:00 2001
From: Pierre Lamot <pierre.lamot@yahoo.fr>
Date: Mon, 14 Jan 2019 15:09:36 +0100
Subject: [PATCH 2/4] accept windows style flags and splitted argument value
- accept windows style flags: /opt or -opt
- accept split arguments : -FhFilename.h or -Fh Filename
---
fxc2.cpp | 194 +++++++++++++++++++++++++++----------------------------
1 file changed, 95 insertions(+), 99 deletions(-)
diff --git a/fxc2.cpp b/fxc2.cpp
index 066608c..01a8d07 100755
--- a/fxc2.cpp
+++ b/fxc2.cpp
@@ -2,7 +2,7 @@
#include <d3dcommon.h>
#include <direct.h>
#include <stdio.h>
-#include <getopt.h>
+#include <assert.h>
#include <string>
#include <wchar.h>
@@ -59,7 +58,41 @@ void print_usage_toomany() {
exit(1);
}
-int main(int argc, char* argv[])
+bool parseOpt( const char* option, int argc, const char** argv, int* index, char** argumentOption )
+{
+ assert(option != NULL);
+ if (!index || *index >= argc) {
+ return false;
+ }
+ const char* argument = argv[*index];
+ if (argument[0] == '-' || argument[0] == '/')
+ argument++;
+ else
+ return false;
+
+ size_t optionSize = strlen(option);
+ if (strncmp(argument, option, optionSize) != 0) {
+ return false;
+ }
+
+ if (argumentOption) {
+ argument += optionSize;
+ if (*argument == '\0') {
+ *index += 1;
+ if (*index >= argc) {
+ printf("Error: missing required argument for option %s\n", option);
+ return false;
+ }
+ *argumentOption = strdup(argv[*index]);
+ } else {
+ *argumentOption = strdup(argument);
+ }
+ }
+ *index += 1;
+ return true;
+}
+
+int main(int argc, const char* argv[])
{
// ====================================================================================
// Process Command Line Arguments
@@ -71,114 +104,77 @@ int main(int argc, char* argv[])
char* entryPoint = NULL;
char* variableName = NULL;
char* outputFile = NULL;
+ char* defineOption = NULL;
int numDefines = 1;
D3D_SHADER_MACRO* defines = new D3D_SHADER_MACRO[numDefines];
defines[numDefines-1].Name = NULL;
defines[numDefines-1].Definition = NULL;
- int i, c;
- static struct option longOptions[] =
- {
- /* These options set a flag. */
- {"nologo", no_argument, &verbose, 0},
- {0, 0, 0, 0}
- };
-
+ int index = 1;
while (1) {
D3D_SHADER_MACRO* newDefines;
- int optionIndex = 0;
- c = getopt_long_only (argc, argv, "T:E:D:V:F:",
- longOptions, &optionIndex);
-
/* Detect the end of the options. */
- if (c == -1)
+ if (index >= argc)
break;
- switch (c)
- {
- case 0:
- //printf ("option -nologo (quiet)\n");
- //Technically, this is any flag we define in longOptions
- break;
- case 'T':
- model = strdup(optarg);
- if(verbose) {
- printf ("option -T (Shader Model/Profile) with arg %s\n", optarg);
- }
- break;
- case 'E':
- entryPoint = strdup(optarg);
- if(verbose) {
- printf ("option -E (Entry Point) with arg %s\n", optarg);
- }
- break;
- case 'D':
- numDefines++;
- //Copy the old array into the new array, but put the new definition at the beginning
- newDefines = new D3D_SHADER_MACRO[numDefines];
- for(i=1; i<numDefines; i++)
- newDefines[i] = defines[i-1];
- delete[] defines;
- defines = newDefines;
- defines[0].Name = strdup(optarg);
- defines[0].Definition = "1";
+ if (parseOpt("nologo", argc, argv, &index, NULL)) {
+ continue;
+ } else if (parseOpt("T", argc, argv, &index, &model)) {
+ if(verbose) {
+ printf ("option -T (Shader Model/Profile) with arg '%s'\n", model);
+ }
+ continue;
+ } else if (parseOpt("E", argc, argv, &index, &entryPoint)) {
+ if(verbose) {
+ printf ("option -E (Entry Point) with arg '%s'\n", entryPoint);
+ }
+ continue;
+ } else if (parseOpt("D", argc, argv, &index, &defineOption)) {
+ numDefines++;
+ //Copy the old array into the new array, but put the new definition at the beginning
+ newDefines = new D3D_SHADER_MACRO[numDefines];
+ for(int i=1; i<numDefines; i++)
+ newDefines[i] = defines[i-1];
+ delete[] defines;
+ defines = newDefines;
+ defines[0].Name = defineOption;
+ defines[0].Definition = "1";
+ if(verbose) {
+ printf ("option -D with arg %s\n", defineOption);
+ }
+ continue;
+ } else if (parseOpt("Vn", argc, argv, &index, &variableName)) {
+ if(verbose) {
+ printf ("option -Vn (Variable Name) with arg '%s'\n", variableName);
+ }
+ continue;
+ } else if (parseOpt("Vi", argc, argv, &index, NULL)) {
+ if(verbose) {
+ printf("option -Vi (Output include process details) acknowledged but ignored.\n");
+ }
+ continue;
+ } else if (parseOpt("Fh", argc, argv, &index, &outputFile)) {
+ if(verbose) {
+ printf ("option -Fh (Output File) with arg %s\n", outputFile);
+ }
+ continue;
+ } else if (parseOpt("?", argc, argv, &index, NULL)) {
+ print_usage_arg();
+ continue;
+ } else {
+ if (!inputFile)
+ {
+ inputFile = new wchar_t[strlen(argv[index])+1];
+ mbstowcs(inputFile, argv[index], strlen(argv[index])+1);
if(verbose) {
- printf ("option -D with arg %s\n", optarg);
- }
- break;
-
- case 'V':
- switch(optarg[0])
- {
- case 'n':
- variableName = strdup(&optarg[1]);
- if(verbose) {
- printf ("option -Vn (Variable Name) with arg %s\n", &optarg[1]);
- }
- break;
- case 'i':
- if(verbose) {
- printf("option -Vi (Output include process details) acknowledged but ignored.\n");
- }
- break;
- default:
- print_usage_arg();
- break;
+ wprintf(L"input file: %ls\n", inputFile);
}
- break;
- case 'F':
- switch(optarg[0])
- {
- case 'h':
- outputFile = strdup(&optarg[1]);
- if(verbose) {
- printf ("option -Fh (Output File) with arg %s\n", &optarg[1]);
- }
- break;
- default:
- print_usage_arg();
- break;
- }
- break;
-
- case '?':
- default:
- print_usage_arg();
- break;
- }
- }
-
- if (optind < argc) {
- inputFile = new wchar_t[strlen(argv[optind])+1];
- mbstowcs(inputFile, argv[optind], strlen(argv[optind])+1);
- if(verbose) {
- wprintf(L"input file: %ls\n", inputFile);
- }
-
- optind++;
- if(optind < argc) {
- print_usage_toomany();
+ index += 1;
+ } else {
+ print_usage_toomany();
+ return 1;
+ }
}
}
@@ -243,7 +239,7 @@ int main(int argc, char* argv[])
wprintf(L"\t %ls,\n", inputFile);
printf("\t");
- for(i=0; i<numDefines-1; i++)
+ for(int i=0; i<numDefines-1; i++)
printf(" %s=%s", defines[i].Name, defines[i].Definition);
printf(",\n");
@@ -315,7 +311,7 @@ int main(int argc, char* argv[])
errno_t err = fopen_s(&f, outputFile, "w");
fprintf(f, "const signed char %s[] =\n{\n", variableName);
- for (i = 0; i < len; i++) {
+ for (int i = 0; i < len; i++) {
fprintf(f, "%4i", outString[i]);
if (i != len - 1)
fprintf(f, ",");
--
2.19.1

156
contrib/src/fxc2/fxc Executable file
View File

@ -0,0 +1,156 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import sys
import os
import platform
import subprocess
import shutil
def log_error(msg: str):
sys.stderr.write(msg + os.linesep)
def toSystemPath(path: str):
absPath = os.path.abspath(path)
if platform.system() == 'Windows':
return absPath
if platform.system() == 'Linux':
pathCmd = None
if shutil.which('cygpath'):
pathCmd = 'cygpath'
elif shutil.which('wslpath'):
pathCmd = 'wslpath'
else:
pathCmd = 'wine winepath'
# convert to hybrid mode to avoid forward slashes in shell
sub = subprocess.Popen([pathCmd, '-m', absPath], shell=False, stderr=subprocess.DEVNULL, stdout=subprocess.PIPE)
errcode = sub.wait()
if errcode != 0:
log_error('failed to find Windows path using {} for "{}"'.format(pathCmd, absPath))
exit(1)
p, err = sub.communicate()
return p.decode('utf-8').strip()
def main():
this_path = os.path.dirname(os.path.abspath(sys.argv[0]))
if (os.path.exists( os.path.join( this_path, 'fxc2.exe'))):
fxc2 = os.path.join( this_path, 'fxc2.exe')
elif (os.path.exists( os.path.join( this_path, 'fxc2'))):
fxc2 = os.path.join( this_path, 'fxc2')
else:
log_error('fxc2 not found in {}'.format(this_path))
exit(1)
nologo = False
optimized = True
entry_point = None
model = None
output_file = None
input_files = []
argi = 0
while argi < len(sys.argv)-1:
argi = argi+1
option = sys.argv[argi]
# --version
if option == '--version':
print('fxc wrapper 0.0.1')
exit(0)
# /nologo
if option == '/nologo' or option == '-nologo':
nologo = True
# /E
elif option == '/E' or option == '-E':
if argi+1 >= len(sys.argv):
log_error('missing /E parameter')
exit(1)
argi = argi+1
entry_point = sys.argv[argi]
# /T
elif option == '/T' or option == '-T':
if argi+1 >= len(sys.argv):
log_error('missing /T parameter')
exit(1)
argi = argi+1
model = sys.argv[argi]
# /Fo
elif option == '/Fo' or option == '-Fo':
if argi+1 >= len(sys.argv):
log_error('missing /Fo parameter')
exit(1)
argi = argi+1
output_file = sys.argv[argi]
output_mode = '-O'
# /Fh
elif option == '/Fh' or option == '-Fh':
if argi+1 >= len(sys.argv):
log_error('missing /Fo parameter')
exit(1)
argi = argi+1
output_file = sys.argv[argi]
output_mode = '-Fh'
# /Od
elif option == '/Od' or option == '-Od':
optimized = False
elif option.startswith('-'):
log_error('unknown option {}'.format(option))
exit(1)
elif option.startswith('/') and not os.path.exists(option):
log_error('unknown option {}'.format(option))
exit(1)
else:
input_files.append(option)
if len(input_files) == 0:
log_error('missing input file(s)')
exit(1)
fxc2_call = [ fxc2 ]
if nologo:
fxc2_call.append( '-nologo' )
if entry_point:
fxc2_call.append( '-E' )
fxc2_call.append( entry_point )
if model:
fxc2_call.append( '-T' )
fxc2_call.append( model )
if output_file:
fxc2_call.append( output_mode )
fxc2_call.append( toSystemPath(output_file) )
for input in input_files:
fxc2_call.append( toSystemPath(input) )
# disabling optimizations not supported by fxc2
# qsb used this to disable debugging(!)
# if not optimized:
# fxc2_call.append( '-Od' )
if platform.system() == 'Windows':
call = subprocess.Popen(fxc2_call, shell=False, stderr=subprocess.DEVNULL, stdout=subprocess.PIPE)
else:
if not nologo:
print('calling fxc2 through wine')
call = subprocess.Popen(['bash', '-c', 'wine ' +' '.join(fxc2_call)], shell=False, stderr=subprocess.DEVNULL, stdout=subprocess.PIPE)
errcode = call.wait()
p, err = call.communicate()
if not nologo:
print('fxc calling ' + ' '.join(fxc2_call))
if not nologo or errcode != 0:
lines = p.decode('utf-8')
print(lines)
exit(errcode)
if __name__ == "__main__":
main()

View File

@ -15,8 +15,8 @@ $(TARBALLS)/fxc2-$(FXC2_VERSION).tar.xz:
fxc2: fxc2-$(FXC2_VERSION).tar.xz .sum-fxc2
$(UNPACK)
cp $(SRC)/fxc2/fxc $(UNPACK_DIR)
$(APPLY) $(SRC)/fxc2/0001-make-Vn-argument-as-optional-and-provide-default-var.patch
$(APPLY) $(SRC)/fxc2/0002-accept-windows-style-flags-and-splitted-argument-val.patch
$(APPLY) $(SRC)/fxc2/0004-Revert-Fix-narrowing-conversion-from-int-to-BYTE.patch
$(APPLY) $(SRC)/fxc2/0001-handle-O-option-to-write-to-a-binary-file-rather-tha.patch
$(APPLY) $(SRC)/fxc2/0002-fix-redefinition-warning.patch
@ -47,5 +47,6 @@ endif
cd $< && $(FXC2_CXX) -static fxc2.cpp -o fxc2.exe
install -d "$(PREFIX)/bin" && \
install $</fxc2.exe "$(PREFIX)/bin" && \
install $</fxc "$(PREFIX)/bin" && \
install $</$(FXC2_DLL) "$(PREFIX)/bin/d3dcompiler_47.dll"
touch $@