Last active
August 16, 2022 07:35
-
-
Save gvanem/fc1ea4f887b9cd03babc611b8350be59 to your computer and use it in GitHub Desktop.
GNU Makefile for PortAudio. Using MinGW, clang-cl or MSVC. Currently for x86 only. Ref. http://www.portaudio.com/
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # | |
| # Gnu Makefile for PortAudio (MSVC + clang-cl). | |
| # | |
| # By G. Vanem <gvanem@yahoo.no> 2014 - 2022. | |
| # | |
| THIS_FILE = Makefile.Windows | |
| TODAY = $(shell date +%d-%B-%Y) | |
| comma := , | |
| # | |
| # Set 'MDEPEND=' to NOT rebuild everything when this file changes. | |
| # It might be a good idea to delete '.depend.Windows' too. | |
| # | |
| MDEPEND = $(THIS_FILE) | |
| USE_ASIO ?= 0 | |
| USE_DSOUND ?= 1 | |
| USE_WASAPI ?= 1 | |
| USE_WDMKS ?= 1 | |
| USE_WMME ?= 1 | |
| USE_DLLs ?= 1 | |
| USE_CRT_STATIC ?= 0 | |
| USE_CRT_DEBUG ?= 0 | |
| USE_CPP_BINDINGS ?= 0 # Not yet | |
| # | |
| # Enable the 'PA_LOGAPI(x)' macros. | |
| # | |
| # This prints details to 'stderr' or 'OutputDebugString()'. | |
| # Calling the internal function 'PaUtil_SetDebugPrintFunction()', the | |
| # debug-output could be sent to anything. A nicer colourised function? | |
| # | |
| USE_API_LOGGING ?= 0 | |
| USE_COLOUR_DEBUG ?= 0 | |
| USE_OutputDebugString ?= 1 | |
| # | |
| # Enable the 'PA_DEBUG(x)' macros. | |
| # | |
| # This gives much more details in addition to 'USE_API_LOGGING=1'. | |
| # As above, this gets sent to 'stderr' or 'OutputDebugString()' | |
| # depending on 'USE_OutputDebugString=1'. | |
| # | |
| USE_DEBUG_OUTPUT ?= 0 | |
| # | |
| # For the '%.i' pre-processing rules below. | |
| # | |
| USE_CLANG_FORMATER ?= 1 | |
| PYTHON ?= py -3 | |
| # | |
| # See below | |
| # | |
| ASIOSDK_ROOT ?= ./old-stuff/ASIOSDK | |
| VPATH = src/common \ | |
| src/os \ | |
| src/hostapi/dsound \ | |
| qa \ | |
| qa/looback/src | |
| # | |
| # From 'vcpkg.json' | |
| # | |
| VER_MAJOR = 19 | |
| VER_MINOR = 8 | |
| VER_MICRO = 0 | |
| VERSION = $(VER_MAJOR).$(VER_MINOR).$(VER_MICRO) ($(TODAY)) | |
| define Usage | |
| Usage: make -f $(THIS_FILE) <CPU=x86 | x64> CC=[cl | clang-cl] [all | depend | clean | vclean | programs | examples] | |
| Specify CC=cl - use MSVC | |
| Specify CC=clang-cl - use clang-cl | |
| endef | |
| ifeq ($(CPU),x86) | |
| BITS = 32 | |
| else ifeq ($(CPU),x64) | |
| BITS = 64 | |
| else | |
| $(error Unsupported CPU=$(CPU)) | |
| endif | |
| # | |
| # This confuses 'clang-cl'. Drop it. | |
| # | |
| export CL= | |
| OBJ_DIR = objects | |
| RCFLAGS = -nologo | |
| ifeq ($(CC),cl) | |
| RCFLAGS += -D_MSC_VER | |
| else ifeq ($(CC),clang-cl) | |
| RCFLAGS += -D__clang__ | |
| else | |
| $(error $(Usage)) | |
| endif | |
| # | |
| # For MSVC / clang-cl: | |
| # Change paths to suite your setup: | |
| # | |
| # E.g. 'VCToolkitInstallDir=f:\gv\VC_2017\VC\Tools\MSVC\%VC_VER%' is the root of my MSVC tools. | |
| # | |
| # I prefer this method over the 'vcvars.bat / 'vcvarsall.bat' inventions of the MSVC team. | |
| # | |
| TOOLS_ROOT = $(realpath $(VCToolkitInstallDir)) | |
| CL_CC = $(TOOLS_ROOT)/bin/HostX86/$(CPU)/cl.exe | |
| CL_LIB = $(TOOLS_ROOT)/bin/HostX86/$(CPU)/lib.exe | |
| CRT_DIR = $(TOOLS_ROOT)/lib/$(CPU) | |
| # | |
| # You could create an env-var: | |
| # "set CLANG_CC=clang-cl.bat -m32" | |
| # or "set CLANG_CC=clang-cl.bat -m64" | |
| # | |
| # And the 'clang-cl.bat' (a file on PATH) should have content like this: | |
| # @echo off | |
| # setlocal | |
| # set CL_32=f:\ProgramFiler\LLVM-5-32bit << install base of your 32-bit Clang | |
| # set CL_64=f:\ProgramFiler\LLVM-5-64bit << ditto for 64-bit | |
| # set CL= << since this could confuse clang-cl | |
| # if %1. == -m32. ( | |
| # shift | |
| # %CL_32%\bin\clang-cl.exe %* | |
| # ) else if %1. == -m64. ( | |
| # shift | |
| # %CL_64%\bin\clang-cl.exe %* | |
| # ) else ( | |
| # clang-cl.exe %* | |
| # ) | |
| # | |
| # Put this 'clang-cl.bat' in a directory on %PATH. | |
| # This way you can easily switch between 32 / 64-bit | |
| # clang-cl builds. | |
| # | |
| CLANG_CC ?= clang-cl.bat -m$(BITS) | |
| # | |
| # Gets "forced included" in every .c/.cpp-file. | |
| # | |
| GENERATED = portaudio_config.h | |
| CFLAGS = -nologo -Zi -Zo -I. -D_CRT_SECURE_NO_WARNINGS -FI./portaudio_config.h -DUNICODE -D_UNICODE | |
| LDFLAGS = -nologo -debug -incremental:no -verbose -machine:$(CPU) | |
| ifeq ($(USE_CRT_STATIC),1) | |
| MD = MT | |
| else | |
| MD = MD | |
| endif | |
| ifeq ($(USE_CRT_DEBUG),1) | |
| CFLAGS += -$(MD)d -RTCc -RTCs -RTCu -GS -fp:except -Gs | |
| else | |
| CFLAGS += -$(MD) -Oi -Ot -Oy -arch:AVX2 -fp:precise -Qpar -Gs0 | |
| endif | |
| # | |
| # We should never need 'oldnames.lib' | |
| # | |
| LDFLAGS += -nodefaultlib:oldnames.lib | |
| # | |
| # The path for the CRT libraries. | |
| # | |
| LDFLAGS += -libpath:$(CRT_DIR) | |
| # | |
| # 'WindowsKits' root is in $(WK_ROOT) and | |
| # 'WindowsKits' version is in $(WK_VER). | |
| # | |
| # Hence the User-Mode libraries for 'x86' are in: | |
| # $(WK_ROOT)/Lib/$(WK_VER)/um/x86/ | |
| # | |
| LDFLAGS += -libpath:$(realpath $(WK_ROOT)/Lib/$(WK_VER)/um/$(CPU)) | |
| # | |
| # Ditto mess for the Universal CRT libraries: for 'x86' the UCRT libs are in: | |
| # $(WK_ROOT)/Lib/$(WK_VER)/ucrt/x86/ | |
| # | |
| LDFLAGS += -libpath:$(realpath $(WK_ROOT)/Lib/$(WK_VER)/ucrt/$(CPU)) | |
| ifeq ($(USE_CRT_DEBUG),1) | |
| D = _d | |
| endif | |
| CFLAGS += -I./include -I./src/common -I./src/os/win | |
| # | |
| # Not yet | |
| # | |
| ifeq ($(USE_COLOUR_DEBUG),1) | |
| LIB_C_SRC = src/os/win/pa_colour_debug.c | |
| endif | |
| # | |
| # Warning control. | |
| # TODO: use #pragmas in 'portaudio_config.h' instead? | |
| # | |
| ifeq ($(CC),clang-cl) | |
| CFLAGS += -W3 \ | |
| -Wno-unused-function \ | |
| -Wno-unused-variable \ | |
| -Wno-unused-value \ | |
| -Wno-unused-command-line-argument \ | |
| -Wno-writable-strings \ | |
| -Wno-missing-braces \ | |
| -Wno-sometimes-uninitialized \ | |
| -Wno-unknown-pragmas \ | |
| -Wno-braced-scalar-init \ | |
| -Wno-deprecated-declarations \ | |
| -Wno-incompatible-pointer-types \ | |
| -Wno-macro-redefined \ | |
| -Wno-microsoft-enum-forward-reference \ | |
| -Wno-implicit-int-float-conversion \ | |
| -Wno-int-conversion \ | |
| -Wno-int-to-pointer-cast \ | |
| -Wno-format \ | |
| -Wno-switch | |
| else | |
| CFLAGS += -W3 -wd4005 -wd4018 -wd4024 -wd4133 -wd4146 -wd4244 -wd4267 -wd4305 -wd4477 -wd4996 | |
| endif | |
| # | |
| # The following codes assumes you have MSys/Cygwin's echo with colour support. | |
| # | |
| BRIGHT_GREEN = \e[1;32m | |
| BRIGHT_WHITE = \e[1;37m | |
| colour_msg = @echo -e "$(1)\e[0m" | |
| green_msg = $(call colour_msg,$(BRIGHT_GREEN)$(strip $(1))) | |
| white_msg = $(call colour_msg,$(BRIGHT_WHITE)$(strip $(1))) | |
| default: all | |
| # | |
| # Some checks for required tools | |
| # | |
| path_find = $(word 1, $(wildcard $(addsuffix /$(strip $(1)),$(subst ;, ,$(subst \,/,$(PATH)))))) | |
| file_exist = $(wildcard $(1)) | |
| ifeq ($(CC),cl) | |
| _CC = $(CL_CC) | |
| CXX = $(_CC) | |
| check_cc: | |
| ifeq ($(call file_exist,$(CL_CC)),) | |
| $(error "$(CL_CC)" not found. Edit $(THIS_FILE) manually.) | |
| else | |
| $(call green_msg, Assuming $(CL_CC) is okay.) | |
| endif | |
| else ifeq ($(CC),clang-cl) | |
| CLANG_CC = $(call path_find, clang-cl.bat) | |
| _CC = clang-cl.bat -m$(BITS) | |
| CXX = $(_CC) | |
| check_cc: | |
| ifeq ($(CLANG_CC),) | |
| $(error "$(CLANG_CC)" not found on PATH. Edit $(THIS_FILE) manually.) | |
| else | |
| $(call white_msg, clang-cl found as: $(CLANG_CC).) | |
| endif | |
| endif | |
| # | |
| # $(LIB_C_SRC): Sources for $(PA_DLL) | |
| # | |
| LIB_C_SRC += $(addprefix src/os/win/, \ | |
| pa_win_coinitialize.c \ | |
| pa_win_hostapis.c \ | |
| pa_win_util.c \ | |
| pa_win_waveformat.c \ | |
| pa_win_wdmks_utils.c) | |
| ifeq ($(USE_WMME),1) | |
| LIB_C_SRC += src/hostapi/wmme/pa_win_wmme.c | |
| endif | |
| ifeq ($(USE_WDMKS),1) | |
| LIB_C_SRC += src/hostapi/wdmks/pa_win_wdmks.c | |
| endif | |
| ifeq ($(CPU),x86) | |
| LIB_C_SRC += src/os/win/pa_x86_plain_converters.c | |
| endif | |
| LIB_C_SRC += $(addprefix src/common/, \ | |
| pa_allocation.c \ | |
| pa_converters.c \ | |
| pa_cpuload.c \ | |
| pa_debugprint.c \ | |
| pa_dither.c \ | |
| pa_front.c \ | |
| pa_process.c \ | |
| pa_ringbuffer.c \ | |
| pa_stream.c \ | |
| pa_trace.c) | |
| ifeq ($(USE_DSOUND),1) | |
| LIB_C_SRC += $(addprefix src/hostapi/dsound/, \ | |
| pa_win_ds.c \ | |
| pa_win_ds_dynlink.c) | |
| endif | |
| ifeq ($(USE_WASAPI),1) | |
| LIB_C_SRC += src/hostapi/wasapi/pa_win_wasapi.c | |
| endif | |
| ifeq ($(USE_ASIO),1) | |
| VPATH += src/hostapi/asio | |
| CFLAGS += -I$(ASIOSDK_ROOT)/common \ | |
| -I$(ASIOSDK_ROOT)/host \ | |
| -I$(ASIOSDK_ROOT)/host/pc | |
| LIB_CPP_SRC += $(ASIOSDK_ROOT)/common/asio.cpp \ | |
| $(ASIOSDK_ROOT)/host/asiodrivers.cpp \ | |
| $(ASIOSDK_ROOT)/host/pc/asiolist.cpp | |
| LIB_CPP_SRC += $(addprefix src/hostapi/asio/, \ | |
| iasiothiscallresolver.cpp \ | |
| pa_asio.cpp) | |
| endif | |
| PROGRAM_SRC = $(addprefix test/, \ | |
| pa_minlat.c \ | |
| patest1.c \ | |
| patest_buffer.c \ | |
| patest_callbackstop.c \ | |
| patest_clip.c \ | |
| patest_converters.c \ | |
| patest_dither.c \ | |
| patest_dsound_find_best_latency_params.c \ | |
| patest_dsound_surround.c \ | |
| patest_hang.c \ | |
| patest_in_overflow.c \ | |
| patest_latency.c \ | |
| patest_leftright.c \ | |
| patest_longsine.c \ | |
| patest_many.c \ | |
| patest_maxsines.c \ | |
| patest_mono.c \ | |
| patest_multi_sine.c \ | |
| patest_out_underflow.c \ | |
| patest_prime.c \ | |
| patest_read_record.c \ | |
| patest_ringmix.c \ | |
| patest_sine8.c \ | |
| patest_sine_channelmaps.c \ | |
| patest_sine_formats.c \ | |
| patest_sine_srate.c \ | |
| patest_sine_time.c \ | |
| patest_start_stop.c \ | |
| patest_stop.c \ | |
| patest_stop_playout.c \ | |
| patest_suggested_vs_streaminfo_latency.c \ | |
| patest_sync.c \ | |
| patest_timing.c \ | |
| patest_toomanysines.c \ | |
| patest_two_rates.c \ | |
| patest_underflow.c \ | |
| patest_unplug.c \ | |
| patest_wire.c \ | |
| patest_wmme_find_best_latency_params.c \ | |
| patest_write_stop.c) | |
| ifeq ($(USE_WASAPI),1) | |
| PROGRAM_SRC += test/patest_jack_wasapi.c | |
| endif | |
| PABLIO_SRC = $(addprefix pablio/, \ | |
| test_rw.c \ | |
| test_rw_echo.c \ | |
| test_w_saw.c \ | |
| test_w_saw8.c) | |
| EXAMPLES_SRC = $(addprefix examples/, \ | |
| paex_mono_asio_channel_select.c \ | |
| paex_ocean_shore.c \ | |
| paex_pink.c \ | |
| paex_read_write_wire.c \ | |
| paex_record.c \ | |
| paex_record_file.c \ | |
| paex_saw.c \ | |
| paex_sine.c \ | |
| paex_wmme_ac3.c \ | |
| paex_wmme_surround.c \ | |
| paex_write_sine.c \ | |
| paex_write_sine_nonint.c \ | |
| pa_devs.c \ | |
| pa_fuzz.c) | |
| EXAMPLES_CPP_SRC = examples/paex_sine_c++.cpp | |
| QA_SRC = $(addprefix qa/, \ | |
| paqa_devs.c \ | |
| paqa_errs.c \ | |
| paqa_latency.c \ | |
| loopback/src/paqa.c) | |
| QA_LOOPBACK_SRC = $(addprefix qa/loopback/src/, \ | |
| audio_analyzer.c \ | |
| biquad_filter.c \ | |
| paqa_tools.c \ | |
| test_audio_analyzer.c \ | |
| write_wav.c) | |
| LIB_OBJ = $(LIB_C_SRC:.c=.obj) \ | |
| $(LIB_CPP_SRC:.cpp=.obj) | |
| QA_OBJ = $(QA_SRC:.c=.obj) | |
| QA_LOOPBACK_OBJ = $(QA_LOOPBACK_SRC:.c=.obj) | |
| EXAMPLES_OBJ = $(EXAMPLES_SRC:.c=.obj) | |
| EXAMPLES_CPP_OBJ = $(EXAMPLES_CPP_SRC:.cpp=.obj) | |
| PROGRAM_OBJ = $(PROGRAM_SRC:.c=.obj) | |
| PABLIO_OBJ = $(PABLIO_SRC:.c=.obj) | |
| PROGRAMS = $(addprefix bin/, \ | |
| $(notdir $(PROGRAM_OBJ:.obj=.exe)) \ | |
| $(notdir $(QA_OBJ:.obj=.exe)) ) | |
| ifeq ($(USE_ASIO),1) | |
| PROGRAMS += bin/asio_hostsample.exe | |
| endif | |
| # | |
| # Impossible; out-dated. | |
| # | |
| PABLIO_PROGS = $(addprefix bin/, \ | |
| $(notdir $(PABLIO_OBJ:.obj=.exe))) | |
| EXAMPLES = $(addprefix bin/, \ | |
| $(notdir $(EXAMPLES_OBJ:.obj=.exe) \ | |
| $(EXAMPLES_CPP_OBJ:.obj=.exe)) ) | |
| $(PABLIO_OBJ) pablio/pablio.obj: EXTRA_CFLAGS = -DRingBuffer=PaUtilRingBuffer \ | |
| -DPortAudioStream=void \ | |
| -DPaTimestamp=AudioTimeStamp | |
| # | |
| # GNU make will assume these objects are intermediate and delete them unless | |
| # they're marked as '.SECONDARY'. | |
| # | |
| .SECONDARY: $(PROGRAM_OBJ) $(EXAMPLES_OBJ) $(EXAMPLES_CPP_OBJ) $(QA_OBJ) $(QA_LOOPBACK_OBJ) | |
| # | |
| # DLL and library names: | |
| # | |
| PA_DLL = bin/portaudio-$(CPU)$(D).dll | |
| PA_STAT_LIB = lib/portaudio$(D)-$(CPU).lib | |
| PA_IMP_LIB = lib/portaudio$(D)_imp-$(CPU).lib | |
| DLL_LIBS = winmm.lib ole32.lib user32.lib advapi32.lib | |
| ifeq ($(USE_DLLs),1) | |
| PROG_INT_LIB = $(PA_IMP_LIB) | |
| PROG_EXT_LIBS = user32.lib | |
| else | |
| PROG_INT_LIB = $(PA_STAT_LIB) | |
| PROG_EXT_LIBS = $(DLL_LIBS) | |
| endif | |
| TARGETS = $(PA_DLL) $(PA_IMP_LIB) $(PA_STAT_LIB) | |
| all: check_cc mk_dirs $(GENERATED) $(TARGETS) epilogue | |
| epilogue: | |
| $(call green_msg, Welcome to PortAudio (CC=$(CC)).) | |
| $(call green_msg, Now you can do a $(BRIGHT_WHITE)make -f $(THIS_FILE) CC=$(CC) programs examples$(BRIGHT_GREEN) too.) | |
| mk_dirs: | |
| -mkdir --parents bin lib | |
| $(OBJ_DIR): | |
| -mkdir $@ | |
| pablio: $(PABLIO_PROGS) | |
| programs: $(PROGRAMS) | |
| examples: $(EXAMPLES) | |
| docs: | |
| doxygen Doxyfile 2> doxygen.log | |
| @echo 'Doxygen done. Look in "doxygen.log" for messages.' | |
| portaudio_config.h: $(MDEPEND) | |
| $(call Generate, $@, //) | |
| $(file >> $@,$(PORTAUDIO_CONFIG_H)) | |
| $(PA_IMP_LIB): $(PA_DLL) | |
| $(PA_DLL): mk_dirs $(LIB_OBJ) $(OBJ_DIR)/portaudio$(D)-$(CPU).def $(OBJ_DIR)/portaudio-$(CPU).res | |
| $(call link_DLL, $@, $(PA_IMP_LIB), $(OBJ_DIR)/portaudio$(D)-$(CPU).def, $(LIB_OBJ) $(OBJ_DIR)/portaudio-$(CPU).res $(DLL_LIBS)) | |
| $(OBJ_DIR)/portaudio$(D)-$(CPU).def: $(LIB_OBJ) $(THIS_FILE) | $(OBJ_DIR) | |
| $(call create_def_file, $@, $(LIB_OBJ)) | |
| $(PA_STAT_LIB): $(LIB_OBJ) | |
| $(call create_static_lib, $@, $^) | |
| %.obj: %.c | $(CC).args | |
| $(call C_compile, $@, $<) | |
| %.obj: %.cpp | $(CC)++.args | |
| $(call CPP_compile, $@, $<) | |
| $(OBJ_DIR)/%.res: $(OBJ_DIR)/%.rc portaudio_config.h | |
| $(call create_res_file, $@, $<) | |
| $(CC).args: $(THIS_FILE) | |
| $(call white_msg, All CFLAGS are in $@) | |
| $(call create_resp_file, $@, -c $(CFLAGS) $(C_ONLY_WARNINGS)) | |
| $(CC)++.args: $(THIS_FILE) | |
| $(call white_msg, All CFLAGS for C++ are in $@) | |
| $(call create_resp_file, $@, -c -TP -EHsc $(CFLAGS)) | |
| # | |
| # For .c-files in VPATH: | |
| # | |
| %.i: %.c $(GENERATED) cpp-filter.py FORCE | |
| $(call C_preprocess, $<, $@) | |
| # | |
| # Use explicit rules for the rest | |
| # | |
| %.i: examples/%.c $(GENERATED) cpp-filter.py FORCE | |
| $(call C_preprocess, $<, $@) | |
| %.i: src/hostapi/wasapi/%.c $(GENERATED) cpp-filter.py FORCE | |
| $(call C_preprocess, $<, $@) | |
| %.i: test/%.c $(GENERATED) cpp-filter.py FORCE | |
| $(call C_preprocess, $<, $@) | |
| FORCE: | |
| $(OBJ_DIR)/portaudio-$(CPU).rc: $(MDEPEND) | $(OBJ_DIR) | |
| $(call Generate, $@, //) | |
| $(file >> $@, $(PORTAUDIO_RC)) | |
| bin/%.exe: loopback/src/%.obj $(QA_LOOPBACK_OBJ) $(PROG_INT_LIB) | |
| $(call link_EXE, $@, $^ $(PROG_EXT_LIBS)) | |
| bin/%.exe: test/%.obj $(PROG_INT_LIB) | |
| $(call link_EXE, $@, $^ $(PROG_EXT_LIBS)) | |
| bin/%.exe: examples/%.obj $(PROG_INT_LIB) | |
| $(call link_EXE, $@, $^ $(PROG_EXT_LIBS)) | |
| bin/%.exe: pablio/%.obj pablio/pablio.obj $(PROG_INT_LIB) | |
| $(call link_EXE, $@, $^ $(PROG_EXT_LIBS)) | |
| bin/%.exe: %.obj $(PROG_INT_LIB) | |
| $(call link_EXE, $@, $^ $(PROG_EXT_LIBS)) | |
| asio_hostsample_OBJ = $(ASIOSDK_ROOT)/common/asio.obj \ | |
| $(ASIOSDK_ROOT)/host/asiodrivers.obj \ | |
| $(ASIOSDK_ROOT)/host/pc/asiolist.obj \ | |
| $(ASIOSDK_ROOT)/host/sample/hostsample.obj | |
| $(asio_hostsample_OBJ): EXTRA_CFLAGS = -I$(ASIOSDK_ROOT)/common \ | |
| -I$(ASIOSDK_ROOT)/host \ | |
| -I$(ASIOSDK_ROOT)/host/pc | |
| # | |
| # MUST use the static PA library here. | |
| # | |
| bin/asio_hostsample.exe: $(asio_hostsample_OBJ) $(PA_STAT_LIB) | |
| $(call link_EXE, $@, $^ $(DLL_LIBS)) | |
| clean: clean_doxy | |
| rm -fr $(OBJ_DIR) | |
| rm -f $(LIB_OBJ) \ | |
| $(PROGRAM_OBJ) \ | |
| $(PABLIO_OBJ) \ | |
| $(EXAMPLES_OBJ) \ | |
| $(EXAMPLES_CPP_OBJ) \ | |
| $(QA_OBJ) \ | |
| $(QA_LOOPBACK_OBJ) \ | |
| $(asio_hostsample_OBJ) \ | |
| src/hostapi/asio/*.obj | |
| rm -f $(GENERATED) link.args cl.args clang-cl.args cl++.args clang-cl++.args \ | |
| .depend.Windows cpp-filter.py check-for-unused-libs.py | |
| clean_doxy: | |
| rm -f doxygen.log | |
| rm -fr doc/html | |
| vclean realclean: clean | |
| rm -f $(TARGETS) $(TARGETS:.dll=.map) \ | |
| $(PABLIO_PROGS) $(PABLIO_PROGS:.exe=.map) \ | |
| $(PROGRAMS) $(PROGRAMS:.exe=.map) \ | |
| $(EXAMPLES) $(EXAMPLES:.exe=.map) \ | |
| $(TEST_OBJ) filtered*.wav paloopback_*.wav \ | |
| link.tmp vc1*.pdb $(TARGETS:.dll=.pdb) $(PROGRAMS:.exe=.pdb) $(PABLIO_PROGS:.exe=.pdb) $(EXAMPLES:.exe=.pdb) | |
| - rmdir bin lib | |
| # | |
| # GNU-make macros: | |
| # | |
| define C_compile | |
| $(_CC) @$(CC).args $(EXTRA_CFLAGS) -Fo./$(strip $(1) $(2)) | |
| @echo | |
| endef | |
| define CPP_compile | |
| $(CXX) @$(CC)++.args $(EXTRA_CFLAGS) -Fo./$(strip $(1) $(2)) | |
| @echo | |
| endef | |
| define Warning | |
| $(1) | |
| $(1) DO NOT EDIT! This file was automatically generated | |
| $(1) from $(realpath $(THIS_FILE)) at $(TODAY). | |
| $(1) Edit that file instead. | |
| $(1) | |
| endef | |
| define Generate | |
| $(call green_msg, Generating $(1)) | |
| $(file > $(1),$(call Warning,$(2))) | |
| endef | |
| # | |
| # Create a response file $(1). | |
| # One word from $(2) per line. | |
| # | |
| define create_resp_file | |
| $(file > $(1)) | |
| $(foreach f, $(2), $(file >> $(1),$(strip $(f))) ) | |
| endef | |
| define link_EXE | |
| $(call green_msg, Linking $(1)) | |
| $(call create_resp_file, link.args, $(LDFLAGS) $(2)) | |
| link -out:$(strip $(1)) @link.args > link.tmp | |
| @cat link.tmp >> $(1:.exe=.map) | |
| @echo | |
| endef | |
| # | |
| # Create a DLL + import-lib from objects $(O): | |
| # arg1, $(1): The .dll file. | |
| # arg2, $(2): The import-lib. | |
| # arg3, $(3): The .def-file. | |
| # arg4, $(4): The .obj file(s), extra args and libs. | |
| # | |
| define link_DLL | |
| $(call green_msg, Linking $(1)) | |
| $(call create_resp_file, link.args, $(LDFLAGS) -dll -implib:$(strip $(2)) -def:$(strip $(3)) $(4)) | |
| link -out:$(strip $(1)) @link.args > link.tmp | |
| @cat link.tmp >> $(1:.dll=.map) | |
| @rm -f $(2:.lib=.exp) | |
| @echo | |
| endef | |
| # | |
| # For C-preprocessing. | |
| # | |
| C_preprocess = $(_CC) -E $(CFLAGS) $(1) | $(PYTHON) cpp_filter.py | |
| ifeq ($(USE_CLANG_FORMATER),1) | |
| C_preprocess += | clang-format -style=Mozilla -assume-filename=c > $(2) | |
| else | |
| C_preprocess += > $(2) | |
| endif | |
| # | |
| # Create a static library. | |
| # | |
| define create_static_lib | |
| $(call green_msg, Creating static lib $(1)) | |
| @rm -f $(1) | |
| lib -nologo -machine:$(CPU) -out:$(strip $(1)) $(2) | |
| @echo | |
| endef | |
| # | |
| # Create a .res-file: | |
| # arg1: $(1): the name of the .res-file. | |
| # arg2: $(2): the .rc-file. | |
| # | |
| define create_res_file | |
| rc $(RCFLAGS) -Fo./$(strip $(1) $(2)) | |
| @echo | |
| endef | |
| # | |
| # Create a .def-file: | |
| # arg1: $(1): the name of the .def-file. | |
| # arg2: $(2): the .obj-files or library to extract symbols from. | |
| # | |
| # If 'USE_ASIO=0', there are no '?ASIO' C++ symbols to extract. | |
| # So just leave it there w/o an extra 'ifeq ()' test. | |
| # | |
| # Symbol prefixes between x86, x64, fastcall and C++ is a mess. | |
| # In x64, the __fastcall do NOT have a '@' prefix. | |
| # And C++ symbols have the same '?' for all combinations it seems. | |
| # | |
| PA_prefixes = ?ASIO | |
| ifeq ($(CPU),x86) | |
| PA_prefixes += _Pa | |
| replace_code_pattern = -e 's/^.* _/ /' | |
| replace_data_pattern = -e 's/^.* _\(.*\)/ \1 DATA/' | |
| else | |
| PA_prefixes += Pa | |
| replace_code_pattern = -e 's/^.* / /' | |
| replace_data_pattern = -e 's/^.* \(.*\)/ \1 DATA/' | |
| endif | |
| # | |
| # For C++ code/data symbols | |
| # | |
| replace_code_pattern += -e 's/^.* ?/ ?/' | |
| replace_data_pattern += -e 's/^.* ?/ ?/' | |
| extract_code_syms = nm $(1) | grep $(foreach p, $(PA_prefixes), -e ' T $(p).*') | \ | |
| sed $(replace_code_pattern) | |
| extract_data_syms = nm $(1) | grep $(foreach p, $(PA_prefixes), -e ' [CDRU] $(p).*') | \ | |
| sed $(replace_data_pattern) | |
| define create_def_file | |
| $(call Generate, $(1), ;) | |
| $(file >> $(1), LIBRARY $(1:.def=.dll)) | |
| $(file >> $(1), EXPORTS) | |
| @echo ' ; Extracted code + DATA symbols:' >> $(1) | |
| $(call extract_code_syms, $(2)) | sort | uniq >> $(1) | |
| endef | |
| # | |
| # The contents of the generated 'portaudio_config.h'. | |
| # | |
| define PORTAUDIO_CONFIG_H | |
| #ifndef _PORTAUDIO_CONFIG_H | |
| #define _PORTAUDIO_CONFIG_H | |
| #define PA_USE_ASIO $(USE_ASIO) | |
| #define PA_USE_DS $(USE_DSOUND) /* Also known as DirectX */ | |
| #define PA_USE_DSOUND $(USE_DSOUND) | |
| #define PA_USE_WASAPI $(USE_WASAPI) | |
| #define PA_USE_WDMKS $(USE_WDMKS) | |
| #define PA_USE_WMME $(USE_WMME) | |
| #if !defined(RC_INVOKED) | |
| #include <stdint.h> /* Some files uses 'int32_t', but lacks this header */ | |
| #define WINDOWS 1 /* Some ASIO files needs this */ | |
| #define WIN32 1 | |
| #define PAWIN_USE_WDMKS_DEVICE_INFO 1 | |
| #ifndef _WIN32_WINNT | |
| #define _WIN32_WINNT 0x0602 | |
| #endif | |
| #if (PA_USE_DS) | |
| #define PAWIN_USE_DIRECTSOUNDFULLDUPLEXCREATE 1 | |
| #endif | |
| #define _USE_MATH_DEFINES /* For a preciser 'M_PI' */ | |
| #include <math.h> | |
| /* | |
| * Enable 'PA_LOGAPI()' and/or 'PA_DEBUG()' | |
| */ | |
| #if ($(USE_API_LOGGING)) /* The value of '$$(USE_API_LOGGING)' */ | |
| #define PA_LOG_API_CALLS 1 | |
| #endif | |
| #if ($(USE_DEBUG_OUTPUT)) /* The value of '$$(USE_DEBUG_OUTPUT)' */ | |
| #define PA_ENABLE_DEBUG_OUTPUT 1 | |
| #endif | |
| #if ($(USE_COLOUR_DEBUG)) /* The value of '$$(USE_COLOUR_DEBUG)' */ | |
| #if !defined(PA_LOG_API_CALLS) && \ | |
| !defined(PA_ENABLE_DEBUG_OUTPUT) | |
| #error "'USE_DEBUG_OUTPUT' and/or 'USE_API_LOGGING' should be 1 to use 'USE_COLOUR_DEBUG'." | |
| #endif | |
| #define PA_ENABLE_COLOUR_DEBUG 1 | |
| #elif ($(USE_OutputDebugString)) /* The value of '$$(USE_OutputDebugString)' */ | |
| #define PA_ENABLE_MSVC_DEBUG_OUTPUT 1 | |
| #endif | |
| #else /* !RC_INVOKED */ | |
| #include <winver.h> | |
| #if (PA_USE_ASIO) | |
| #define RC_BUILTIN_ASIO " ASIO" | |
| #else | |
| #define RC_BUILTIN_ASIO "" | |
| #endif | |
| #if (PA_USE_DS || PA_USE_DSOUND) | |
| #define RC_BUILTIN_DSOUND " DSound" | |
| #else | |
| #define RC_BUILTIN_DSOUND "" | |
| #endif | |
| #if (PA_USE_WDMKS) | |
| #define RC_BUILTIN_WDMKS " WDMKS" | |
| #else | |
| #define RC_BUILTIN_WDMKS "" | |
| #endif | |
| #if (PA_USE_WMME) | |
| #define RC_BUILTIN_WMME " WMME" | |
| #else | |
| #define RC_BUILTIN_WMME "" | |
| #endif | |
| #if (PA_USE_WASAPI) | |
| #define RC_BUILTIN_WASAPI " WASAPI" | |
| #else | |
| #define RC_BUILTIN_WASAPI "" | |
| #endif | |
| #if ($(USE_CRT_DEBUG)) /* The value of '$$(USE_CRT_DEBUG)' */ | |
| #define RC_DBG_REL "debug" | |
| #define RC_FILEFLAGS 1 | |
| #else | |
| #define RC_DBG_REL "release" | |
| #define RC_FILEFLAGS 0 | |
| #endif | |
| #if defined(__clang__) | |
| #define RC_HOST "clang" | |
| #elif defined(_MSC_VER) | |
| #define RC_HOST "MSVC" | |
| #else | |
| #error "Unknown 'RC_HOST'." | |
| #endif | |
| #define RC_VERSION $(VER_MAJOR),$(VER_MINOR),$(VER_MICRO),0 | |
| #define RC_DESCRIPTION "PortAudio shared library ($(CPU), " RC_HOST ", " RC_DBG_REL ")" | |
| #endif /* RC_INVOKED */ | |
| #endif /* _PORTAUDIO_CONFIG_H */ | |
| endef | |
| ifeq ($(USER),gv) | |
| PRIVATE_BUILD = "Private build of <gvanem@yahoo.no>" | |
| else | |
| PRIVATE_BUILD = | |
| endif | |
| define PORTAUDIO_RC | |
| #include "portaudio_config.h" | |
| //APPICON ICON "portaudio.ico" /** \todo Create and add a nice icon. */ | |
| VS_VERSION_INFO VERSIONINFO | |
| FILEVERSION RC_VERSION | |
| PRODUCTVERSION RC_VERSION | |
| FILEFLAGSMASK 0x3fL | |
| FILEOS VOS__WINDOWS32 | |
| FILETYPE VFT_DLL | |
| FILESUBTYPE 0x0L | |
| FILEFLAGS RC_FILEFLAGS | |
| BEGIN | |
| BLOCK "StringFileInfo" | |
| BEGIN | |
| BLOCK "040904b0" | |
| BEGIN | |
| VALUE "CompanyName", "PortAudio, http://www.portaudio.com/" | |
| VALUE "FileDescription", RC_DESCRIPTION | |
| VALUE "FileVersion", "$(VERSION)" | |
| VALUE "InternalName", "PortAudio" | |
| VALUE "OriginalFilename", "$(notdir $(PA_DLL))" | |
| VALUE "ProductName", "PortAudio DLL for $(CPU) programs." | |
| VALUE "ProductVersion", "$(VERSION)" | |
| VALUE "LegalCopyright", "Copyright (c) 1999-2018 Ross Bencina and Phil Burk" | |
| VALUE "PrivateBuild", $(PRIVATE_BUILD) | |
| VALUE "Comments", "Built on $(TODAY).\n" \ | |
| "\t\t\tWith:" \ | |
| RC_BUILTIN_ASIO \ | |
| RC_BUILTIN_DSOUND \ | |
| RC_BUILTIN_WDMKS \ | |
| RC_BUILTIN_WMME \ | |
| RC_BUILTIN_WASAPI "." | |
| END | |
| END | |
| BLOCK "VarFileInfo" | |
| BEGIN | |
| VALUE "Translation", 0x409, 1200 | |
| END | |
| END | |
| endef | |
| cpp-filter.py: ../Common.Windows | |
| $(call green_msg, Generating $@) | |
| $(file > $@,#!/usr/env/python) | |
| $(file >> $@,if 1:) | |
| $(file >> $@,$(cpp_filter_PY)) | |
| check-for-unused-libs.py: ../Common.Windows | |
| $(call green_msg, Generating $@) | |
| $(file > $@,#!/usr/env/python) | |
| $(file >> $@,if 1:) | |
| $(file >> $@,$(check_for_unused_libs_PY)) | |
| define cpp_filter_PY | |
| import sys | |
| empty_lines = 0 | |
| while True: | |
| line = sys.stdin.readline() | |
| if not line: | |
| break | |
| line = line.rstrip() | |
| if line == "": | |
| empty_lines += 1 | |
| continue | |
| # | |
| # MSVC or clang-cl 'line' directive | |
| # | |
| if line.startswith("#line") or line.startswith("# "): | |
| line = line.replace (r"\\", "/") | |
| print (line) | |
| if line == "}" or line == "};": | |
| print ("") | |
| print ("Removed %d empty lines." % empty_lines, file=sys.stderr) | |
| endef | |
| define check_for_unused_libs_PY | |
| # | |
| # Check a MSVC .map-file for lines after a 'Unused libraries:' | |
| # | |
| import os, sys | |
| map_file = sys.argv[1] | |
| ignore_libs = [ ] | |
| class State(): | |
| IDLE = 0 | |
| UNUSED = 1 | |
| class Colour(): | |
| RED = WHITE = RESET = "" | |
| try: | |
| from colorama import init, Fore, Style | |
| init() | |
| Colour.RED = Fore.RED + Style.BRIGHT | |
| Colour.WHITE = Fore.WHITE + Style.BRIGHT | |
| Colour.RESET = Style.RESET_ALL | |
| except: | |
| pass | |
| # | |
| # This seems to come from '<omp.h>': '#pragma comment(lib, "vcomp")' | |
| # via some Qt header. Just ignore it. | |
| # | |
| ignore_libs += [ "vcomp.lib" ] | |
| def report (unused): | |
| num = len(unused) | |
| plural = [ "library", "libraries" ] | |
| if num > 0: | |
| print ("%s%d unused %s in %s:%s" % (Colour.RED, num, plural[num > 1], map_file, Colour.RESET)) | |
| for u in sorted(unused): | |
| print (" " + u) | |
| print ("%sDone%s\n" % (Colour.WHITE, Colour.RESET)) | |
| def process_map (state): | |
| unused_libs = [] | |
| with open (map_file, "rt") as f: | |
| lines = f.readlines() | |
| for l in lines: | |
| l = l.strip() | |
| if l == "Unused libraries:": | |
| state = State.UNUSED | |
| continue | |
| if state == State.UNUSED: | |
| if l == "": | |
| break | |
| if os.path.basename (l).lower() not in ignore_libs: | |
| unused_libs.append (l) | |
| return unused_libs | |
| report (process_map(State.IDLE)) | |
| endef | |
| DEP_REPLACE = sed -e 's/\(.*\)\.o: /\n\1.$$(O): /' | |
| DEP_CFLAGS = -m32 -MM $(filter -I%, $(CFLAGS)) --include ./portaudio_config.h | |
| ALL_SOURCES = $(LIB_C_SRC) \ | |
| $(LIB_CPP_SRC) \ | |
| $(PROGRAM_SRC) \ | |
| $(EXAMPLES_SRC) \ | |
| $(EXAMPLES_CPP_SRC) \ | |
| $(QA_SRC) \ | |
| $(QA_LOOPBACK_SRC) | |
| # | |
| # The ouput is not correct; the .obj files should contain the directory of the .c/.cpp-file. | |
| # But how to do that with gcc/sed? | |
| # | |
| depend: $(GENERATED) | |
| $(call green_msg, Generating dependencies for $(words $(ALL_SOURCES)) source files...) | |
| $(file > .depend.Windows,$(call Warning,#)) | |
| gcc $(DEP_CFLAGS) $(ALL_SOURCES) | $(DEP_REPLACE) >> .depend.Windows | |
| -include .depend.Windows | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment