Skip to content

Instantly share code, notes, and snippets.

@gvanem
Last active August 16, 2022 07:35
Show Gist options
  • Select an option

  • Save gvanem/fc1ea4f887b9cd03babc611b8350be59 to your computer and use it in GitHub Desktop.

Select an option

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/
#
# 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