port dll to clang-cl

really need to figure out why the stupid thing isn't working properly
This commit is contained in:
Lily Tsuru 2024-07-19 07:45:18 -04:00
parent cc59c0c6db
commit 510d3547a2
10 changed files with 49 additions and 39 deletions

View file

@ -1,18 +1,14 @@
build: build:
dotnet build -c Release dotnet build -c Release
make -C speech2 CONFIG=Release -j$(nproc) make -C speech2 CONFIG=Release -j$(nproc)
cp speech2/bin/x86/Release/speech2.dll SAPIServer/bin/Release/net40/windows-x86 cp speech2/bin/x86/Release/speech2.dll SAPIServer/bin/Release/net40/windows-x86
cp /usr/i686-w64-mingw32/bin/libgcc_s_dw2-1.dll SAPIServer/bin/Release/net40/windows-x86/ cp speech2/bin/x86/Release/speech2.pdb SAPIServer/bin/Release/net40/windows-x86
cp /usr/i686-w64-mingw32/bin/libstdc++-6.dll SAPIServer/bin/Release/net40/windows-x86/
build-debug: build-debug:
dotnet build -c Debug dotnet build -c Debug
make -C speech2 CONFIG=Release -j$(nproc) make -C speech2 CONFIG=Debug -j$(nproc)
cp speech2/bin/x86/Debug/speech2.dll SAPIServer/bin/Debug/net40/windows-x86
cp speech2/bin/x86/Release/speech2.dll SAPIServer/bin/Debug/net40/windows-x86 cp speech2/bin/x86/Debug/speech2.pdb SAPIServer/bin/Debug/net40/windows-x86
cp /usr/i686-w64-mingw32/bin/libgcc_s_dw2-1.dll SAPIServer/bin/Debug/net40/windows-x86/
cp /usr/i686-w64-mingw32/bin/libstdc++-6.dll SAPIServer/bin/Debug/net40/windows-x86/
clean: clean:
rm -rf SAPIServer/bin SAPIServer/obj rm -rf SAPIServer/bin SAPIServer/obj

View file

@ -6,8 +6,11 @@ Simple HTTP frontend API for Microsoft Speech API
Requirements Requirements
- .NET SDK - .NET SDK
- VS2022 lib pack (TODO: link)
- mingw-w64 toolchain built with `win32` thread model (`pthread` won't work) - mingw-w64 toolchain built with `win32` thread model (`pthread` won't work)
You'll also need to chattr +F (or mount the whole thing with `ciopfs` and rename the headers to lowercase, if not on ext4 or you don't want to tune2fs) the windows sdk header directories so the build works.
`just` should do the trick. `just` should do the trick.
## Running ## Running

View file

@ -38,16 +38,16 @@ namespace SAPIServer {
internal class SpeechDLL { internal class SpeechDLL {
private const string Speech2DLL = "speech2.dll"; private const string Speech2DLL = "speech2.dll";
[DllImport(Speech2DLL, CallingConvention = CallingConvention.Cdecl)] [DllImport(Speech2DLL, CallingConvention = CallingConvention.StdCall)]
public static extern IntPtr speech2_create_api(EngineType type); public static extern IntPtr speech2_create_api(EngineType type);
[DllImport(Speech2DLL, CallingConvention = CallingConvention.Cdecl)] [DllImport(Speech2DLL, CallingConvention = CallingConvention.StdCall)]
public static extern void speech2_destroy_api(IntPtr pAPI); public static extern void speech2_destroy_api(IntPtr pAPI);
[DllImport(Speech2DLL, CallingConvention = CallingConvention.Cdecl)] [DllImport(Speech2DLL, CallingConvention = CallingConvention.StdCall)]
public static extern int speech2_api_get_voiceinfo_count(IntPtr pAPI); public static extern int speech2_api_get_voiceinfo_count(IntPtr pAPI);
[DllImport(Speech2DLL, CallingConvention = CallingConvention.Cdecl)] [DllImport(Speech2DLL, CallingConvention = CallingConvention.StdCall)]
public static extern IntPtr speech2_api_get_voiceinfo_index(IntPtr pAPI, int index); public static extern IntPtr speech2_api_get_voiceinfo_index(IntPtr pAPI, int index);
} }
@ -63,6 +63,8 @@ namespace SAPIServer {
} }
public List<VoiceDef> GetVoices() { public List<VoiceDef> GetVoices() {
Console.WriteLine("SpeechAPI.GetVoices()");
var count = SpeechDLL.speech2_api_get_voiceinfo_count(handle); var count = SpeechDLL.speech2_api_get_voiceinfo_count(handle);
Console.WriteLine($"count {count}"); Console.WriteLine($"count {count}");
var list = new List<VoiceDef>(); var list = new List<VoiceDef>();

View file

@ -7,6 +7,9 @@ TYPE = dll
# Any C++ file in src/ is automatically picked up. # Any C++ file in src/ is automatically picked up.
CXXSRCS = $(wildcard src/*.cpp) $(wildcard src/*/*.cpp) CXXSRCS = $(wildcard src/*.cpp) $(wildcard src/*/*.cpp)
# Required libraries.
LIBS = kernel32.lib shell32.lib user32.lib uuid.lib ole32.lib
.PHONY: all clean matrix .PHONY: all clean matrix
include build/rules.mk include build/rules.mk

View file

@ -1,33 +1,32 @@
# Base compiler flags. Only change if you *explicitly* know what you're doing. # Base compiler flags. Only change if you *explicitly* know what you're doing.
CXXRTDIR = $(VCDIR)/crt CXXRTDIR = $(VCDIR)/crt
UCRTDIR = $(VCDIR)/ucrt UCRTDIR = $(VCDIR)/ucrt
PSDKDIR = $(VCDIR)/winsdk PSDKDIR = $(VCDIR)/winsdk
# TODO: Switch to debug builds
Release_RTLIBS = libcmt.lib libucrt.lib libvcruntime.lib libcpmt.lib Release_RTLIBS = libcmt.lib libucrt.lib libvcruntime.lib libcpmt.lib
Debug_RTLIBS = libcmtd.lib libucrtd.lib libvcruntimed.lib libcpmtd.lib Debug_RTLIBS = libcmtd.lib libucrtd.lib libvcruntimed.lib libcpmtd.lib
# I really should rename this x_x # I really should rename this x_x
CLANG_FLAGS = -fms-extensions -fms-compatibility-version=19 -isystem $(CXXRTDIR)/include -isystem $(UCRTDIR)/include -isystem $(PSDKDIR)/include/shared -isystem $(PSDKDIR)/include/um CLANG_FLAGS = -fms-extensions -fms-compatibility-version=19 -isystem $(CXXRTDIR)/include -isystem $(UCRTDIR)/include -isystem $(PSDKDIR)/include/shared -isystem $(PSDKDIR)/include/um
BASE_FLAGS = -MMD -g3 -fvisibility=hidden $(CLANG_FLAGS) -march=pentium3 -Iinclude -Isrc -Ithird_party -D_WIN32_WINNT=0x0501 BASE_FLAGS = -MMD -gcodeview -fvisibility=hidden $(CLANG_FLAGS) -march=pentium-mmx -Iinclude -Isrc -Ithird_party -mstack-alignment=4 -D_WIN32_WINNT=0x0501
BASE_CCFLAGS = $(BASE_FLAGS) -std=gnu17 BASE_CCFLAGS = $(BASE_FLAGS) -std=gnu17
BASE_CXXFLAGS = $(BASE_FLAGS) -std=c++20 BASE_CXXFLAGS = $(BASE_FLAGS) -std=c++20
BASE_LDFLAGS_SHARED = /dll BASE_LDFLAGS_SHARED = /dll
BASE_LDFLAGS = /nodefaultlib /version:5.1 /machine:i386 /subsystem:console,5.1 /libpath:$(CXXRTDIR)/lib/x86 /libpath:$(UCRTDIR)/lib /libpath:$(PSDKDIR)/lib BASE_LDFLAGS = /nodefaultlib /version:5.1 /machine:i386 /subsystem:windows,5.1 /libpath:$(CXXRTDIR)/lib/x86 /libpath:$(UCRTDIR)/lib /libpath:$(PSDKDIR)/lib
# TODO: Figure out what optimizations are safe and don't break the stack
Release_Valid = yes Release_Valid = yes
Release_CCFLAGS = -O3 -DNDEBUG Release_CCFLAGS = -O0 -DNDEBUG
Release_CXXFLAGS = -O3 -DNDEBUG Release_CXXFLAGS = -O0 -DNDEBUG
Release_LDFLAGS = /debug /pdb:$(BINDIR)/$(NAME).pdb Release_LDFLAGS = /debug /pdb:$(BINDIR)/$(NAME).pdb
Debug_Valid = yes Debug_Valid = yes
Debug_CCFLAGS = -O0 -g -DDEBUG Debug_CCFLAGS = -O0 -DDEBUG # -D_DEBUG
Debug_CXXFLAGS = -O0 -g -DDEBUG Debug_CXXFLAGS = -O0 -DDEBUG # -D_DEBUG -D_ITERATOR_DEBUG_LEVEL=0
Debug_LDFLAGS = /debug /pdb:$(BINDIR)/$(NAME).pdb Debug_LDFLAGS = /debug /pdb:$(BINDIR)/$(NAME).pdb
# select a default configuration or validate configuration # select a default configuration or validate configuration

View file

@ -9,7 +9,7 @@ BUILD_PRODUCT = $(BINDIR)/$(NAME).dll
$(BINDIR)/$(NAME).dll: $(BINDIR)/ $(OBJDIR)/ $(OBJS) $(BINDIR)/$(NAME).dll: $(BINDIR)/ $(OBJDIR)/ $(OBJS)
echo -e "\e[92mLinking DLL $@\e[0m" echo -e "\e[92mLinking DLL $@\e[0m"
$(LD) $(BASE_LDFLAGS_SHARED) $(BASE_LDFLAGS) $($(CONFIG)_LDFLAGS) $(RTLIBS) $(LIBS) $(OBJS) /out:$@ $(LD) $(BASE_LDFLAGS_SHARED) $(BASE_LDFLAGS) $($(CONFIG)_LDFLAGS) $($(CONFIG)_RTLIBS) $(LIBS) $(OBJS) /out:$@
else else
ifeq ($(TYPE),exe) ifeq ($(TYPE),exe)
BUILD_PRODUCT = $(BINDIR)/$(NAME).exe BUILD_PRODUCT = $(BINDIR)/$(NAME).exe

View file

@ -1,17 +1,17 @@
#include <windows.h> #include <windows.h>
#include "speechapi.hpp" #include "speechapi.hpp"
#define SP2_EXPORT __declspec(dllexport) __cdecl #define SPEECH2_API __declspec(dllexport) WINAPI
// Engine type. Sync with C# // Engine type. Sync with C#
enum class EngineType : int { ET_SAPI4, ET_SAPI5, ET_DECTALK }; enum class EngineType : int { ET_SAPI4, ET_SAPI5, ET_DECTALK };
extern "C" { extern "C" {
SP2_EXPORT void* speech2_create_api(EngineType type) { SPEECH2_API void* speech2_create_api(EngineType type) {
ISpeechAPI* api = nullptr; ISpeechAPI* api = nullptr;
printf("speech2_create_api(%d)\n", type); //printf("speech2_create_api(%d)\n", type);
switch(type) { switch(type) {
case EngineType::ET_SAPI4: case EngineType::ET_SAPI4:
@ -20,6 +20,8 @@ SP2_EXPORT void* speech2_create_api(EngineType type) {
default: return nullptr; default: return nullptr;
} }
printf("api is %p\n", api);
if(auto hr = api->Initialize(); FAILED(hr)) { if(auto hr = api->Initialize(); FAILED(hr)) {
delete api; delete api;
return nullptr; return nullptr;
@ -28,14 +30,14 @@ SP2_EXPORT void* speech2_create_api(EngineType type) {
return static_cast<void*>(api); return static_cast<void*>(api);
} }
SP2_EXPORT void speech2_destroy_api(void* engine) { SPEECH2_API void speech2_destroy_api(void* engine) {
if(engine) if(engine)
delete static_cast<ISpeechAPI*>(engine); delete static_cast<ISpeechAPI*>(engine);
} }
// API bindings TODO // API bindings TODO
SP2_EXPORT int speech2_api_get_voiceinfo_count(void* engine) { SPEECH2_API int speech2_api_get_voiceinfo_count(void* engine) {
if(engine) { if(engine) {
auto* api = static_cast<ISpeechAPI*>(engine); auto* api = static_cast<ISpeechAPI*>(engine);
return api->GetVoices().size(); return api->GetVoices().size();
@ -43,7 +45,7 @@ SP2_EXPORT int speech2_api_get_voiceinfo_count(void* engine) {
return -1; return -1;
} }
SP2_EXPORT const ISpeechAPI::VoiceInfo* speech2_api_get_voiceinfo_index(void* engine, int index) { SPEECH2_API const ISpeechAPI::VoiceInfo* speech2_api_get_voiceinfo_index(void* engine, int index) {
if(engine) { if(engine) {
auto* api = static_cast<ISpeechAPI*>(engine); auto* api = static_cast<ISpeechAPI*>(engine);
return &api->GetVoices()[index]; return &api->GetVoices()[index];

View file

@ -7,7 +7,7 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) {
// have COM initalized by default, so we don't need to do so there. // have COM initalized by default, so we don't need to do so there.
switch(fdwReason) { switch(fdwReason) {
case DLL_PROCESS_ATTACH: case DLL_PROCESS_ATTACH:
CoInitialize(nullptr); //CoInitialize(nullptr);
break; break;
case DLL_THREAD_ATTACH: break; case DLL_THREAD_ATTACH: break;
@ -18,7 +18,7 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) {
if(lpvReserved != nullptr) { if(lpvReserved != nullptr) {
break; // do not do cleanup if process termination scenario break; // do not do cleanup if process termination scenario
} }
CoUninitialize(); //CoUninitialize();
break; break;
} }
return TRUE; return TRUE;

View file

@ -6,6 +6,9 @@
#include "sapi4/include/speech.h" #include "sapi4/include/speech.h"
#include "speechapi.hpp" #include "speechapi.hpp"
// stupid hacky but Whatevers
struct SpeechAPI_SAPI4 : public ISpeechAPI { struct SpeechAPI_SAPI4 : public ISpeechAPI {
virtual ~SpeechAPI_SAPI4() { virtual ~SpeechAPI_SAPI4() {
printf("~SpeechAPI_SAPI4\n"); printf("~SpeechAPI_SAPI4\n");
@ -17,7 +20,7 @@ struct SpeechAPI_SAPI4 : public ISpeechAPI {
}; };
HRESULT Initialize() override { HRESULT Initialize() override {
HRESULT hRes; HRESULT hRes{};
printf("speech2: SpeechAPI_Sapi4::Initalize() begin: %p\n", this); printf("speech2: SpeechAPI_Sapi4::Initalize() begin: %p\n", this);
@ -30,9 +33,13 @@ struct SpeechAPI_SAPI4 : public ISpeechAPI {
printf("speech2: SpeechAPI_Sapi4::Initalize() created enum\n"); printf("speech2: SpeechAPI_Sapi4::Initalize() created enum\n");
printf("speech2: SpeechAPI_Sapi4::Initalize() starting enumvoices\n");
// Fill out voices // Fill out voices
EnumVoices(); EnumVoices();
printf("speech2: SpeechAPI_Sapi4::Initalize() end enumvoices\n");
printf("speech2: SpeechAPI_Sapi4::Initalize() end\n"); printf("speech2: SpeechAPI_Sapi4::Initalize() end\n");
@ -40,19 +47,16 @@ struct SpeechAPI_SAPI4 : public ISpeechAPI {
} }
void EnumVoices() { void EnumVoices() {
TTSMODEINFO found{}; static TTSMODEINFO found{};
DWORD piss = 0;
while(!pEnum->Next(1, &found, nullptr)) {
auto ptr = _strdup(found.szModeName);
while(!pEnum->Next(1, &found, &piss)) {
//auto ptr = strdup(found.szModeName);
printf("EnumVoices() voice %s\n", found.szModeName); printf("EnumVoices() voice %s\n", found.szModeName);
//voices.push_back(VoiceInfo { .guid = found.gModeID, .voiceName = ptr }); voices.push_back({found.gModeID, ptr});
ZeroMemory(&found, sizeof(TTSMODEINFO));
} }
printf("EnumVoices() end\n");
pEnum->Reset(); pEnum->Reset();
} }

View file

@ -13,6 +13,7 @@ struct ISpeechAPI {
//VoiceInfo(VoiceInfo&&) = delete; //VoiceInfo(VoiceInfo&&) = delete;
~VoiceInfo() { ~VoiceInfo() {
// Make this a lot less stupid at some point.
if(voiceName) if(voiceName)
free(voiceName); free(voiceName);
} }