From 60a10666f439216cab1ec231a3c5f5f28a2f5faf Mon Sep 17 00:00:00 2001 From: Aleksander Czajczynski Date: Thu, 10 Oct 2024 14:21:17 +0200 Subject: [PATCH] 2024-10-10 14:21 UTC+0200 Aleksander Czajczynski (hb fki.pl) + config/win/clang-noauto.mk + additional clang flavour checking when the compiler is specified via set HB_COMPILER=clang (not auto-detected) This is important for distributions of clang that bundle both gcc and clang in the same directory. Harbour 3.2 by default prioritize gcc over clang. For example you should be now able to build from winlibs.com by Brecht Sanders with environment setup such as: PATH=C:\winlibs\mingw64\bin;%PATH% HB_COMPILER=clang win-make * config/global.mk ! added workaround for common GNU Make issue with $(dir path with spaces/file) macro, commonly striking on Windows systems under "Program Files", but also possible in other setups. Workaround is to call $(call dir_with_spaces,$(HB_COMP_PATH)). I have only used this workaround in clang detection, but keep this in mind while revisiting detection of another compiler. * config/win/clang.mk * utils/hbmk2/hbmk2.prg * another rework of Clang on Windows detection (ARM64, x86_64, x86), solved problems with different availability of resource compiler, They are now probed in order: windres, llvm-windres, llvm-rc. * added option to use MinGW INPUT(file.o) link scripts for old tools To apply workaround with clang, set HB_USER_DFLAGS=--mingw-script It is not supported in at least some of current clang toolchains, but it's still needed to succesfully build on old ones (those using GNU ld on Windows). --- ChangeLog.txt | 35 +++++++++++++ config/global.mk | 102 +++++++++++++++++++++++++++++-------- config/win/clang-noauto.mk | 90 ++++++++++++++++++++++++++++++++ config/win/clang.mk | 39 +++++++++----- utils/hbmk2/hbmk2.prg | 14 +++++ 5 files changed, 246 insertions(+), 34 deletions(-) create mode 100644 config/win/clang-noauto.mk diff --git a/ChangeLog.txt b/ChangeLog.txt index 2754ccf4db..6f0bc033b9 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -7,6 +7,41 @@ Entries may not always be in chronological/commit order. See license at the end of file. */ +2024-10-10 14:21 UTC+0200 Aleksander Czajczynski (hb fki.pl) + + config/win/clang-noauto.mk + + additional clang flavour checking when the compiler is specified + via set HB_COMPILER=clang (not auto-detected) + + This is important for distributions of clang that bundle both + gcc and clang in the same directory. Harbour 3.2 by default + prioritize gcc over clang. + + For example you should be now able to build from winlibs.com by + Brecht Sanders with environment setup such as: + PATH=C:\winlibs\mingw64\bin;%PATH% + HB_COMPILER=clang + win-make + + * config/global.mk + ! added workaround for common GNU Make issue with + $(dir path with spaces/file) macro, commonly striking on Windows + systems under "Program Files", but also possible in other setups. + Workaround is to call $(call dir_with_spaces,$(HB_COMP_PATH)). + I have only used this workaround in clang detection, but keep + this in mind while revisiting detection of another compiler. + + * config/win/clang.mk + * utils/hbmk2/hbmk2.prg + * another rework of Clang on Windows detection (ARM64, x86_64, x86), + solved problems with different availability of resource compiler, + They are now probed in order: windres, llvm-windres, llvm-rc. + + * added option to use MinGW INPUT(file.o) link scripts for old tools + To apply workaround with clang, set HB_USER_DFLAGS=--mingw-script + It is not supported in at least some of current clang toolchains, + but it's still needed to succesfully build on old ones (those + using GNU ld on Windows). + 2024-10-07 11:40 UTC+0200 Aleksander Czajczynski (hb fki.pl) * config/global.mk ! detect ARM64 CPU on Windows also under non-native shell (MSYS2 sh) diff --git a/config/global.mk b/config/global.mk index ead7c80c31..936317dbb1 100644 --- a/config/global.mk +++ b/config/global.mk @@ -40,6 +40,8 @@ endif # Arbitrary pattern which we do not expect to occur in real-world path names substpat := !@!@ +# On the other hand a very common pattern +chr_space := $(subst ,, ) # This is not strictly necessary, but it does significantly reduce # the number of rules that make has to evaluate otherwise, which may give @@ -79,6 +81,7 @@ find_in_path = $(strip $(subst $(substpat), ,$(firstword $(subst |, ,$(subst find_in_path_raw = $(strip $(subst $(substpat), ,$(firstword $(subst |, ,$(subst $(subst x, ,x),$(substpat),$(filter-out |,$(foreach dir, $(subst $(PTHSEP), ,$(subst $(subst x, ,x),$(substpat),$(PATH))),|$(wildcard $(subst //,/,$(subst $(substpat),\ ,$(subst \,/,$(dir)))/$(1)))))))))) find_in_path_par = $(strip $(subst $(substpat), ,$(firstword $(subst |, ,$(subst $(subst x, ,x),$(substpat),$(filter-out |,$(foreach dir, $(subst $(PTHSEP), ,$(subst $(subst x, ,x),$(substpat),$(2))),|$(wildcard $(subst //,/,$(subst $(substpat),\ ,$(subst \,/,$(dir)))/$(1))$(HB_HOST_BIN_EXT))))))))) find_in_path_prw = $(strip $(subst $(substpat), ,$(firstword $(subst |, ,$(subst $(subst x, ,x),$(substpat),$(filter-out |,$(foreach dir, $(subst $(PTHSEP), ,$(subst $(subst x, ,x),$(substpat),$(2))),|$(wildcard $(subst //,/,$(subst $(substpat),\ ,$(subst \,/,$(dir)))/$(1)))))))))) +dir_with_spaces = $(subst $(substpat), ,$(dir $(subst $(chr_space),$(substpat),$(1)))) # Some presets based on HB_BUILD_NAME ifneq ($(HB_BUILD_NAME),) @@ -708,39 +711,90 @@ ifeq ($(HB_COMPILER),) endif endif else - HB_COMP_PATH := $(call find_in_path,clang) + HB_COMP_PATH := $(call find_in_path_raw,clang.exe) + HB_COMP_PWD := $(call dir_with_spaces,$(HB_COMP_PATH)) ifneq ($(HB_COMP_PATH),) - HB_COMPILER = clang - ifneq ($(wildcard $(dir $(HB_COMP_PATH))aarch64-w64-mingw32-clang$(HB_HOST_BIN_EXT)),) + HB_COMPILER := clang + ifneq ($(wildcard $(HB_COMP_PWD)aarch64-w64-mingw32-clang$(HB_HOST_BIN_EXT)),) HB_CPU := arm64 - ifeq ($(HB_BUILD_NAME),) - export HB_BUILD_NAME := arm64 - endif - ifneq ($(MSYSTEM),) - export MSYSTEM := CLANGARM64 - endif + MSYSTEM := CLANGARM64 else - ifneq ($(wildcard $(dir $(HB_COMP_PATH))x86_64-w64-mingw32-clang$(HB_HOST_BIN_EXT)),) + ifneq ($(wildcard $(HB_COMP_PWD)x86_64-w64-mingw32-clang$(HB_HOST_BIN_EXT)),) HB_CPU := x86_64 - ifeq ($(HB_BUILD_NAME),) - export HB_BUILD_NAME := 64 - endif - ifneq ($(MSYSTEM),) - export MSYSTEM := CLANG64 - endif + MSYSTEM := CLANG64 else - ifneq ($(wildcard $(dir $(HB_COMP_PATH))i686-w64-mingw32-clang$(HB_HOST_BIN_EXT)),) - ifneq ($(MSYSTEM),) - export MSYSTEM := CLANG32 - endif + ifneq ($(wildcard $(HB_COMP_PWD)i686-w64-mingw32-clang$(HB_HOST_BIN_EXT)),) HB_CPU := x86 + MSYSTEM := CLANG32 else - ifneq ($(wildcard $(dir $(HB_COMP_PATH))lldb-vscode$(HB_HOST_BIN_EXT)),) - export MSYSTEM := + ifneq ($(findstring /VC/Tools/Llvm/ARM64/,$(HB_COMP_PATH)),) + MSYSTEM := + HB_CPU := arm64 + else + ifneq ($(findstring /VC/Tools/Llvm/x64/,$(HB_COMP_PATH)),) + MSYSTEM := + HB_CPU := x86_64 + else + ifneq ($(findstring mingw64,$(HB_COMP_PATH)),) + HB_CPU := x86_64 + MSYSTEM := CLANG64 + else + ifneq ($(findstring mingw32,$(HB_COMP_PATH)),) + HB_CPU := x86 + MSYSTEM := CLANG32 + else + MSYSTEM := $(shell clang --version) + ifneq ($(findstring x86_64-pc-windows-msvc,$(MSYSTEM)),) + MSYSTEM := + HB_CPU := x86_64 + else + ifneq ($(findstring i686-pc-windows-msvc,$(MSYSTEM)),) + MSYSTEM := + HB_CPU := x86 + else + ifneq ($(findstring aarch64-pc-windows-msvc,$(MSYSTEM)),) + MSYSTEM := + HB_CPU := arm64 + ifneq ($(findstring x86_64-w64-windows-gnu,$(MSYSTEM)),) + HB_CPU := x86_64 + MSYSTEM := CLANG64 + else + ifneq ($(findstring i686-w64-windows-gnu,$(MSYSTEM)),) + HB_CPU := x86 + MSYSTEM := CLANG32 + else + ifneq ($(findstring aarch64-w64-windows-gnu,$(MSYSTEM)),) + HB_CPU := arm64 + MSYSTEM := CLANGARM64 + else + ifneq ($(findstring -windows-gnu,$(MSYSTEM)),) + MSYSTEM := CLANG + else + MSYSTEM := + endif + endif + endif + endif + endif + endif + endif + endif endif endif endif endif + endif + endif + export MSYSTEM + ifneq ($(HB_CPU),$(HB_HOST_CPU)) + ifeq ($(HB_BUILD_NAME),) + ifeq ($(HB_CPU),x86_64) + export HB_BUILD_NAME := 64 + else + export HB_BUILD_NAME := HB_CPU + endif + endif + endif else HB_COMP_PATH := $(call find_in_path,wcc386) ifneq ($(HB_COMP_PATH),) @@ -1077,6 +1131,10 @@ ifeq ($(HB_COMPILER),) endif endif endif +else + ifneq ($(wildcard $(TOP)$(ROOT)config/$(HB_PLATFORM)/$(HB_COMPILER)-noauto.mk),) + include $(TOP)$(ROOT)config/$(HB_PLATFORM)/$(HB_COMPILER)-noauto.mk + endif endif # auto-detect CC values for given platform/compiler diff --git a/config/win/clang-noauto.mk b/config/win/clang-noauto.mk new file mode 100644 index 0000000000..4bd552e4df --- /dev/null +++ b/config/win/clang-noauto.mk @@ -0,0 +1,90 @@ +# Brecht Sanders winlibs clang distribution and possiblty others are impossible +# to detect from path alone as clang.exe resides in the same directory with gcc, +# in Harbour 3.2 gcc has priority over clang for backwards compatibility + +# supp. actions if the set HB_COMPILER=clang was specified, not auto-detected +ifneq ($(HB_COMPILER_ORI),) + HB_COMP_PATH := $(call find_in_path_raw,clang.exe) + HB_COMP_PWD := $(call dir_with_spaces,$(HB_COMP_PATH)) + ifneq ($(HB_COMP_PATH),) + ifneq ($(wildcard $(HB_COMP_PWD)../x86_64-w64-mingw32/lib/lib*.a),) + MSYSTEM := CLANG64 + HB_CPU := x86_64 + else + ifneq ($(wildcard $(HB_COMP_PWD)../i686-w64-mingw32/lib/lib*.a),) + MSYSTEM := CLANG32 + HB_CPU := x86 + else + ifneq ($(wildcard $(HB_COMP_PWD)../aarch64-w64-mingw32/lib/lib*.a),) + MSYSTEM := CLANGARM64 + HB_CPU := arm64 + else + ifneq ($(findstring /VC/Tools/Llvm/ARM64/,$(HB_COMP_PATH)),) + MSYSTEM := + HB_CPU := arm64 + else + ifneq ($(findstring /VC/Tools/Llvm/x64/,$(HB_COMP_PATH)),) + MSYSTEM := + HB_CPU := x86_64 + else + ifneq ($(findstring mingw64,$(HB_COMP_PWD)),) + MSYSTEM := CLANG64 + else + ifneq ($(findstring mingw32,$(HB_COMP_PWD)),) + MSYSTEM := CLANG32 + HB_CPU := x86 + else + MSYSTEM := $(shell clang --version) + ifneq ($(findstring x86_64-pc-windows-msvc,$(MSYSTEM)),) + MSYSTEM := + HB_CPU := x86_64 + else + ifneq ($(findstring i686-pc-windows-msvc,$(MSYSTEM)),) + MSYSTEM := + HB_CPU := x86 + else + ifneq ($(findstring aarch64-pc-windows-msvc,$(MSYSTEM)),) + MSYSTEM := + HB_CPU := arm64 + ifneq ($(findstring x86_64-w64-windows-gnu,$(MSYSTEM)),) + HB_CPU := x86_64 + MSYSTEM := CLANG64 + else + ifneq ($(findstring i686-w64-windows-gnu,$(MSYSTEM)),) + HB_CPU := x86 + MSYSTEM := CLANG32 + else + ifneq ($(findstring aarch64-w64-windows-gnu,$(MSYSTEM)),) + HB_CPU := arm64 + MSYSTEM := CLANGARM64 + else + ifneq ($(findstring -windows-gnu,$(MSYSTEM)),) + MSYSTEM := CLANG + else + MSYSTEM := + endif + endif + endif + endif + endif + endif + endif + endif + endif + endif + endif + endif + endif + endif + export MSYSTEM + ifneq ($(HB_CPU),$(HB_HOST_CPU)) + ifeq ($(HB_BUILD_NAME),) + ifeq ($(HB_CPU),x86_64) + export HB_BUILD_NAME := 64 + else + export HB_BUILD_NAME := HB_CPU + endif + endif + endif + endif +endif diff --git a/config/win/clang.mk b/config/win/clang.mk index 0c1aba9453..708ed48116 100644 --- a/config/win/clang.mk +++ b/config/win/clang.mk @@ -54,6 +54,8 @@ AR := $(HB_CCPREFIX)llvm-ar AR_RULE = ( $(AR) $(ARFLAGS) $(HB_AFLAGS) $(HB_USER_AFLAGS) rcs $(LIB_DIR)/$@ $(^F) $(ARSTRIP) ) || ( $(RM) $(subst /,$(DIRSEP),$(LIB_DIR)/$@) && $(FALSE) ) +# TODO: add resource compiler detect chain in this stage: GNU windres, llvm-windres, llvm-rc + DY := $(CC) DFLAGS += -shared $(LIBPATHS) DY_OUT := -o$(subst x,x, ) @@ -84,24 +86,37 @@ else endef endif +TMPSPEC := @__dyn__.tmp + +# setting HB_USER_DFLAGS=--mingw-script[...] +# may help to workaround if old clang + MinGW linker is in use, +# build may fail either with too long command line or unrecognized argument +ifneq ($(filter --mingw-script, $(HB_USER_DFLAGS)),) + HB_USER_DFLAGS := $(subst --mingw-script,,$(HB_USER_DFLAGS)) + # NOTE: The empty line directly before 'endef' HAS TO exist! + override define dynlib_object + @$(ECHO) $(ECHOQUOTE)INPUT($(subst \,/,$(file)))$(ECHOQUOTE) >> __dyn__.tmp + endef + TMPSPEC := __dyn__.tmp +endif + +define create_dynlib + $(if $(wildcard __dyn__.tmp),@$(RM) __dyn__.tmp,) + $(foreach file,$^,$(dynlib_object)) + $(DY) $(DFLAGS) $(HB_USER_DFLAGS) $(DY_OUT)$(DYN_DIR)/$@ $(TMPSPEC) $(DLIBS) $(IMPLIBFLAGS) $(DYSTRIP) $(DYSTRIP) + $(dynlib_ln) +endef + # clang distributed by MS uses lld-link, libs are *.lib not lib*.a # in opposite MSYS/MinGW needs args to actually make an implib ifeq ($(MSYSTEM),) - define create_dynlib - $(if $(wildcard __dyn__.tmp),@$(RM) __dyn__.tmp,) - $(foreach file,$^,$(dynlib_object)) - $(DY) $(DFLAGS) $(HB_USER_DFLAGS) $(DY_OUT)$(DYN_DIR)/$@ @__dyn__.tmp $(DLIBS) $(DYSTRIP) $(DYSTRIP) - $(dynlib_ln) - endef + LDFLAGS += -Wl,-subsystem:console + DFLAGS += -Wl,-subsystem:console else - define create_dynlib - $(if $(wildcard __dyn__.tmp),@$(RM) __dyn__.tmp,) - $(foreach file,$^,$(dynlib_object)) - $(DY) $(DFLAGS) $(HB_USER_DFLAGS) $(DY_OUT)$(DYN_DIR)/$@ @__dyn__.tmp $(DLIBS) -Wl,--out-implib,$(IMP_FILE),--output-def,$(DYN_DIR)/$(basename $@).def $(DYSTRIP) $(DYSTRIP) - $(dynlib_ln) - endef + IMPLIBFLAGS = -Wl,--out-implib,$(IMP_FILE),--output-def,$(DYN_DIR)/$(basename $@).def endif + DY_RULE = $(create_dynlib) include $(TOP)$(ROOT)config/rules.mk diff --git a/utils/hbmk2/hbmk2.prg b/utils/hbmk2/hbmk2.prg index cbe59d55fa..84bd1bcdf7 100644 --- a/utils/hbmk2/hbmk2.prg +++ b/utils/hbmk2/hbmk2.prg @@ -4368,6 +4368,11 @@ STATIC FUNCTION __hbmk( aArgs, nArgTarget, nLevel, /* @ */ lPause, /* @ */ lExit IF hb_fileExists( hb_DirSepAdd( hbmk[ _HBMK_cHB_INSTALL_LIB ] ) + "hbrtl.lib" ) /* selfcheck if clang ld emits .lib extension */ cLibLibPrefix := "" cLibLibExt := ".lib" + IF hbmk[ _HBMK_lGUI ] + AAdd( hbmk[ _HBMK_aOPTL ], "-Wl,-subsystem:windows" ) + ELSE + AAdd( hbmk[ _HBMK_aOPTL ], "-Wl,-subsystem:console" ) + ENDIF ENDIF CASE hbmk[ _HBMK_cCOMP ] == "tcc" cBin_CompCPP := "tcc.exe" @@ -4571,6 +4576,15 @@ STATIC FUNCTION __hbmk( aArgs, nArgTarget, nLevel, /* @ */ lPause, /* @ */ lExit cBin_Res := hbmk[ _HBMK_cCCPREFIX ] + "windres" + hbmk[ _HBMK_cCCEXT ] cResExt := ".reso" cOpt_Res := "{FR} {IR} -O coff -o {OS}" + IF hbmk[ _HBMK_cCOMP ] == "clang" .AND. FindInPath( cBin_Res ) == NIL + IF FindInPath( cBin_Res := "llvm-" + cBin_Res ) == NIL + cBin_Res := "llvm-rc" + cResExt := ".res" + /* codepage default in llvm-rc is confusing, a .rc file could be multi-language */ + cOpt_Res := "/C 1252 {FR} /FO {OS} {IR}" + ENDIF + ENDIF + IF ! Empty( hbmk[ _HBMK_cCCPATH ] ) cBin_Res := FNameEscape( hbmk[ _HBMK_cCCPATH ] + hb_ps() + cBin_Res, hbmk[ _HBMK_nCmd_Esc ] ) ENDIF