#
# Copyright (C) 2012-2023 Intel Corporation.
# SPDX-License-Identifier: MIT
#

###### Common definitions ######

# In this section we place all the generic flags. Later sections provide
# additional flags depending on architecutre, compiler etc.

## General flags

# If we are testing Pin, add some internal checks. Don't do this by default
# since it may incur a performance penatly.
PIN_TESTFLAGS :=
ifeq ($(PIN_TESTING),1)
    PIN_TESTFLAGS += -slow_asserts
endif

## Output control

COMP_OBJ := /c /Fo
COMP_EXE := /Fe
LINK_EXE := /out:

## Special compilation/linkage directives

STATIC :=
NO_RANDOM := /DYNAMICBASE:NO
NO_ASLR :=
PIC :=
PIE := /FIXED:NO /BASE:0
NO_PIE :=
SSE2 :=
FP387 :=
ASMCPP :=
NO_STDLIBS := /NODEFAULTLIB
EXPORT := /EXPORT:

# Flags to suppress errors when the linker has trouble solving relocations but they are still valid.
SUPPRESS_RELOCS :=

## Include paths

# COMPONENT_INCLUDES will be defined later in the directory structure section.
# APP_INCLUDES and TOOL_INCLUDES are internal utilities for this file.
APP_INCLUDES :=
TOOL_INCLUDES :=

## Library paths

APP_LPATHS :=
TOOL_LPATHS :=
SATOOL_LPATHS :=

## Libraries to link
TOOL_CRT_LIBS := pincrt.lib

ifeq ($(NEWCPP),1)
    TOOL_CRT_LIBS += c++.lib
endif

BIONIC_ARCH := x86
ifneq ($(TARGET),ia32)
    BIONIC_ARCH := x86_64
endif

APP_LIBS :=
DL_LIB :=
APP_LIB_ATOMIC := atomic.lib
APP_LIB_XED := xed.lib
TOOL_LIBS := pin.lib xed.lib pinipc.lib $(TOOL_CRT_LIBS) kernel32.lib
SATOOL_LIBS := $(NO_STDLIBS) $(TOOL_CRT_LIBS) kernel32.lib

## Compiler flags

# Throughout this file, we only fill in the NOOPT versions of these variables.
# At the bottom of the file, the full versions are built from the NOOPT and
# the relevant optimization and debug flags (see below).
# e.g. APP_CXXFLAGS := $(APP_CXXFLAGS_NOOPT) $(APP_OPT_CXX) $(DBG_INFO_CXX)

APP_CXXFLAGS_NOOPT := /nologo /DTARGET_WINDOWS /DFUND_TC_HOSTOS=FUND_OS_WINDOWS \
                      /DFUND_TC_TARGETOS=FUND_OS_WINDOWS /EHa /Gy-

# clang-cl compiler requires those special flags
ifeq ($(COMPILER),clang-cl)
    CLANG_CXXFLAGS := -Wno-non-c-typedef-for-linkage -Wno-microsoft-include -Wno-unicode
    ifeq ($(TARGET),ia32)
        CLANG_CXXFLAGS += -m32 /D__i386__
    else
        CLANG_CXXFLAGS += -m64 /D__LP64__=1
    endif
endif

ASM_FLAGS := /nologo /Cp

# /EHs- /EHa-	Disable exception handling in the tool, otherwise it could interfere in
#				the apllication's exception handling.
# /wd4530              Turn off the warning about not having /EHsc turned on
TOOL_CXXFLAGS_NOOPT := /EHs- /EHa- /wd4530 /DTARGET_WINDOWS /nologo /Gy $(CLANG_CXXFLAGS)
DLL_CXXFLAGS :=
ENABLE_DEPRECATED := /DPIN_DEPRECATED_WARNINGS=0

WINDOWS_H_PATH ?= $(patsubst %\,%,$(strip $(shell cmd /c 'for %i in (Windows.h) do @echo.   %~dp$$INCLUDE:i')))
export WINDOWS_H_PATH
TOOL_CXXFLAGS_NOOPT += /Oi- /GR- /GS- /DPIN_CRT=1 /D_WINDOWS_H_PATH_="$(WINDOWS_H_PATH)"

ifeq ($(TARGET),ia32)
    TOOL_CXXFLAGS_NOOPT += /D__i386__
else
    TOOL_CXXFLAGS_NOOPT += /D__LP64__
endif

# no additional flags are required to support Restricted Transactional Memory on MSVC
RTM_FLAGS :=

## Linker flags

# Throughout this file, we only fill in the NOOPT versions of these variables.
# At the bottom of the file, the full versions are built from the NOOPT and
# the relevant optimization and debug flags (see below).
# e.g. TOOL_LDFLAGS := $(TOOL_LDFLAGS_NOOPT) $(TOOL_OPT_LD) $(DBG_INFO_LD)

APP_LDFLAGS_NOOPT := /link /NOLOGO /INCREMENTAL:NO
# /EXPORT:main	Main function of the tool has to be exported.
# $(NO_STDLIBS)	Do not link and use any system library except for those listed explicitly
#				to avoid conflicts with an application using the same library.
TOOL_LDFLAGS_NOOPT := /DLL /EXPORT:main $(NO_STDLIBS) /NOLOGO /INCREMENTAL:NO /IGNORE:4210 /IGNORE:4049
ifeq ($(TARGET),ia32)
    ifeq ($(COMPILER),clang-cl)
        # Another clang tool's failure requires
        TOOL_LDFLAGS_NOOPT += /safeseh:no
    endif
endif

# Assume options /DYNAMICBASE and /NXCOMPAT are accepted by all supported Windows linkers.
TOOL_LDFLAGS_NOOPT += /DYNAMICBASE /NXCOMPAT
SATOOL_LDFLAGS_NOOPT := /NOLOGO /INCREMENTAL:NO
DLL_LDFLAGS := /DLL

# Flags to link an exe file from a single asm file with main() function as entry point.
APP_LDFLAGS_LINK_ASM := /link /defaultlib:kernel32.lib /defaultlib:user32.lib /entry:main

###### Debugging and optimizations ######

## Debugging flags to be used in any makefile.rules file

# The following variables do not depend on the user-defined DEBUG
# variable. When they are used, debug information will always be
# generated.
# Note: DBG_INFO_CXX_ALWAYS is intentionally defined with deferred expansion.
DBG_INFO_CXX_ALWAYS = /Z7 /Fd
DBG_INFO_LD_ALWAYS := /DEBUG

## Utility variables "internal" to this file

OPT_CXX_DEBUG := /MDd /Od
OPT_CXX := /MD /O2
OPT_LD_DEBUG := /OPT:NOREF
OPT_LD := /OPT:REF
# The following variables depend on the user-defined DEBUG variable.
# If DEBUG=1 was specified, no optimizations will be applied and debug
# information will be generated. Otherwise, full optimization will be
# performed and debug information will not be generated.

ifeq ($(DEBUG),1)
    APP_OPT_CXX := $(OPT_CXX_DEBUG)
    APP_OPT_LD := $(OPT_LD_DEBUG)
    TOOL_OPT_CXX := $(OPT_CXX_DEBUG)
    TOOL_OPT_LD := $(OPT_LD_DEBUG)
    # Note: DBG_INFO_CXX is intentionally defined with deferred expansion.
    DBG_INFO_CXX = $(DBG_INFO_CXX_ALWAYS)
    DBG_INFO_LD := $(DBG_INFO_LD_ALWAYS)
else
    APP_OPT_CXX := $(OPT_CXX)
    APP_OPT_LD := $(OPT_LD)
    TOOL_OPT_CXX := $(OPT_CXX)
    TOOL_OPT_LD := $(OPT_LD)
    DBG_INFO_CXX :=
    DBG_INFO_LD :=
endif

###### Additional flags depending on directory structure ######

ifeq ($(KIT),1)
    # In the kit tree, the default Pin root is the kit root.
    # However, don't overwrite a user-defined PIN_ROOT definition (if it exists)
    PIN_ROOT ?= ../../..
    XED_ROOT := $(PIN_ROOT)/extras/xed-$(TARGET)
    TOOLS_ROOT := $(PIN_ROOT)/source/tools
    
    COMPONENT_INCLUDES := /I$(PIN_ROOT)/extras/components/include
    TOOL_INCLUDES += /I$(PIN_ROOT)/source/include/pin \
                     /I$(PIN_ROOT)/source/include/pin/gen
    ifeq ($(NEWCPP),1)
            TOOL_INCLUDES += -I$(PIN_ROOT)/extras/cxx/include \
                             -I$(PIN_ROOT)/extras
    else
            TOOL_INCLUDES += -I$(PIN_ROOT)/extras/stlport/include \
                             -I$(PIN_ROOT)/extras \
                             -I$(PIN_ROOT)/extras/libstdc++/include
    endif
    TOOL_INCLUDES += -I$(PIN_ROOT)/extras/crt/include \
                     -I$(PIN_ROOT)/extras/crt \
                     -I$(PIN_ROOT)/extras/crt/include/arch-$(BIONIC_ARCH) \
                     -I$(PIN_ROOT)/extras/crt/include/kernel/uapi \
                     -I$(PIN_ROOT)/extras/crt/include/kernel/uapi/asm-x86 \
                     /FIinclude/msvc_compat.h
                         
    APP_LPATHS += /LIBPATH:$(PIN_ROOT)/extras/components/lib/$(TARGET)
    TOOL_LPATHS += /LIBPATH:$(PIN_ROOT)/$(TARGET)/lib \
                   /LIBPATH:$(PIN_ROOT)/$(TARGET)/lib-ext \
                   /LIBPATH:$(PIN_ROOT)/$(TARGET)/runtime/pincrt
    SATOOL_LPATHS += /LIBPATH:$(PIN_ROOT)/$(TARGET)/lib \
                     /LIBPATH:$(PIN_ROOT)/$(TARGET)/lib-ext \
                     /LIBPATH:$(PIN_ROOT)/$(TARGET)/runtime/pincrt

    TOOL_LDFLAGS_NOOPT += $(PIN_ROOT)/$(TARGET)/runtime/pincrt/crtbeginS.obj
    SATOOL_LDFLAGS_NOOPT += /IGNORE:4049 $(PIN_ROOT)/$(TARGET)/runtime/pincrt/crtbegin.obj
        
    PIN := $(PIN_ROOT)/pin
    PINBIN := $(PIN_ROOT)/$(TARGET)/bin/pin$(EXE_SUFFIX)
    PIN32 := $(PIN_ROOT)/ia32/bin/pin$(EXE_SUFFIX)
    PIN64 := $(PIN_ROOT)/intel64/bin/pin$(EXE_SUFFIX)
else
    PIN_ROOT := ../..
    XED_ROOT := $(PIN_ROOT)/build/Source/xed/xed-$(COMPILER)-pin-$(TARGET_OS)-$(TARGET)/xed-kit
    TOOLS_ROOT := $(PIN_ROOT)/PinTools

	COMPONENT_INCLUDES := /I$(PIN_ROOT)/Source/atomic/00-export-include \
                          /I$(PIN_ROOT)/Source/sync/00-export-include \
                          /I$(PIN_ROOT)/Source/util/00-export-include
    TOOL_INCLUDES += /I$(TOOLS_ROOT)/Include \
                     /I$(PIN_ROOT)/build/Source/pin/internal-include-$(TARGET_OS)-$(TARGET)
    ifeq ($(NEWCPP),1)
        TOOL_INCLUDES += /I$(PIN_ROOT)/Source/bionic/c++/llvm/libcxx/v1 \
                         /I$(PIN_ROOT)/Source/bionic
    else
        TOOL_INCLUDES += /I$(PIN_ROOT)/Source/bionic/stlport/stlport \
                         /I$(PIN_ROOT)/Source/bionic \
                         /I$(PIN_ROOT)/Source/bionic/libstdc++/include
    endif
    TOOL_INCLUDES += /I$(PIN_ROOT)/Source/bionic/libc/additional/windows \
                     /I$(PIN_ROOT)/Source/bionic/libc/additional/windows/include \
                     /I$(PIN_ROOT)/Source/bionic/libc/additional/include \
                     /I$(PIN_ROOT)/Source/bionic/libc/include \
                     /I$(PIN_ROOT)/Source/bionic/libc \
                     /I$(PIN_ROOT)/Source/bionic/libm/include \
                     /I$(PIN_ROOT)/Source/bionic/libm \
                     /I$(PIN_ROOT)/Source/bionic/libc/arch-$(BIONIC_ARCH)/include \
                     /I$(PIN_ROOT)/Source/bionic/libc/kernel/uapi \
                     /I$(PIN_ROOT)/Source/bionic/libc/kernel/uapi/asm-x86 \
                     /I$(PIN_ROOT)/Source/os-apis/00-export-include \
                     /I$(PIN_ROOT)/Source/asm/00-export-include \
                     /FIinclude/msvc_compat.h

    TOOL_LDFLAGS_NOOPT += $(PIN_ROOT)/build/Source/bionic/libc/export-$(TARGET_OS)-$(HOST_ARCH)-$(TARGET_OS)-$(TARGET)/$(TARGET)/crtbeginS.obj
    SATOOL_LDFLAGS_NOOPT += /IGNORE:4049 $(PIN_ROOT)/build/Source/bionic/libc/export-$(TARGET_OS)-$(HOST_ARCH)-$(TARGET_OS)-$(TARGET)/$(TARGET)/crtbegin.obj

    PINCRT_LIBPATH := $(PIN_ROOT)/build/Source/bionic/stlport/export-$(TARGET_OS)-$(HOST_ARCH)-$(TARGET_OS)-$(TARGET)/$(TARGET) \
                      $(PIN_ROOT)/build/Source/bionic/libm/export-$(TARGET_OS)-$(HOST_ARCH)-$(TARGET_OS)-$(TARGET)/$(TARGET) \
                      $(PIN_ROOT)/build/Source/bionic/libc/export-$(TARGET_OS)-$(HOST_ARCH)-$(TARGET_OS)-$(TARGET)/$(TARGET) \
                      $(PIN_ROOT)/build/Source/os-apis/export-$(TARGET_OS)-$(HOST_ARCH)-$(TARGET_OS)-$(TARGET)/$(TARGET)

    APP_LPATHS += /LIBPATH:$(PIN_ROOT)/build/Source/pin/internal-include-$(TARGET_OS)-$(TARGET)/lib
    TOOL_LPATHS += /LIBPATH:$(PIN_ROOT)/build/Source/pin/pin-$(TARGET_OS)-$(TARGET) \
                   $(foreach dir,$(PINCRT_LIBPATH),/LIBPATH:$(dir))
    SATOOL_LPATHS += /LIBPATH:$(PIN_ROOT)/build/Source/pin/pin-$(TARGET_OS)-$(TARGET) \
                     $(foreach dir,$(PINCRT_LIBPATH),/LIBPATH:$(dir))

    PIN := $(PIN_ROOT)/build/Source/pin/pin-$(TARGET_OS)-$(TARGET)/pin$(EXE_SUFFIX)
    PINBIN := $(PIN_ROOT)/build/Source/pin/pin-$(TARGET_OS)-$(TARGET)/pin$(EXE_SUFFIX)
	PIN32 := $(PIN_ROOT)/build/Source/pin/pin-$(TARGET_OS)-ia32/pin$(EXE_SUFFIX)
	PIN64 := $(PIN_ROOT)/build/Source/pin/pin-$(TARGET_OS)-intel64/pin$(EXE_SUFFIX)
endif

TOOL_INCLUDES += $(COMPONENT_INCLUDES) \
                 /I$(XED_ROOT)/include/xed \
                 /I$(TOOLS_ROOT)/Utils \
                 /I$(TOOLS_ROOT)/InstLib
APP_INCLUDES += /I$(TOOLS_ROOT)/Utils

APP_LPATHS += /LIBPATH:$(XED_ROOT)/lib
TOOL_LPATHS += /LIBPATH:$(XED_ROOT)/lib
SATOOL_LPATHS += /LIBPATH:$(XED_ROOT)/lib

###### Additional flags depending on the compiler ######
# All our compilers (cl, clang-cl, icx-cc) run on top of 
# some Visual Studio environment, so resolving these settings for all.

# VisualStudioVersion == 15  -> VS2017
# VisualStudioVersion == 16  -> VS2019
# VisualStudioVersion == 17  -> VS2022
MSVCVER_GE_15 = 0
MSVCVER_GE_16 = 0
MSVCVER_GE_17 = 0
ifeq ($(VisualStudioVersion),15.0)
MSVCVER_GE_15 = 1
else ifeq ($(VisualStudioVersion),16.0)
MSVCVER_GE_15 = 1
MSVCVER_GE_16 = 1
else ifeq ($(VisualStudioVersion),17.0)
MSVCVER_GE_15 = 1
MSVCVER_GE_16 = 1
MSVCVER_GE_17 = 1
endif

# Suppress thread-safe local static initialization feature of C++ 11 using VS2015/2017/2019/2022 compilers
# These flags should be used with clang-cl and icx-cl too.
TOOL_CXXFLAGS_NOOPT += /Zc:threadSafeInit- /Zc:sizedDealloc-
ifeq ($(MSVCVER_GE_16), 1)
	TOOL_CXXFLAGS_NOOPT += /wd5208
endif

###### Additional flags depending on architecture ######

ifeq ($(TARGET),ia32)
    APP_CXXFLAGS_NOOPT += /DTARGET_IA32 /DHOST_IA32 /DFUND_TC_TARGETCPU=FUND_CPU_IA32 /DFUND_TC_HOSTCPU=FUND_CPU_IA32
    TOOL_CXXFLAGS_NOOPT += /DTARGET_IA32 /DHOST_IA32
    ASM_FLAGS += /DTARGET_IA32
    TOOL_LDFLAGS_NOOPT += /MACHINE:x86 /ENTRY:Ptrace_DllMainCRTStartup@12
    SSE2 := /arch:SSE2
endif

ifeq ($(TARGET),intel64)
    APP_CXXFLAGS_NOOPT += /DTARGET_IA32E /DHOST_IA32E /DFUND_TC_TARGETCPU=FUND_CPU_INTEL64 /DFUND_TC_HOSTCPU=FUND_CPU_INTEL64
    TOOL_CXXFLAGS_NOOPT += /DTARGET_IA32E /DHOST_IA32E
    ASM_FLAGS += /DTARGET_IA32E
    TOOL_LDFLAGS_NOOPT += /MACHINE:x64 /ENTRY:Ptrace_DllMainCRTStartup
    NO_ASLR := /HIGHENTROPYVA:NO
endif

###### Finalize flags ######

## Compiler and linker flags

# Add the include paths to the compilation flags.
APP_CXXFLAGS_NOOPT += $(APP_INCLUDES)
TOOL_CXXFLAGS_NOOPT += $(TOOL_INCLUDES)
# MASM supports only 10 include directories so we have to be very picky...
ASM_FLAGS += /I$(TOOLS_ROOT)/InstLib

ifeq ($(NEWCPP),1)
    APP_CXXFLAGS_NOOPT += /D_LIBCPP_DISABLE_AVAILABILITY /D_LIBCPP_NO_VCRUNTIME /D__BIONIC__
    TOOL_CXXFLAGS_NOOPT += /D_LIBCPP_DISABLE_AVAILABILITY /D_LIBCPP_NO_VCRUNTIME /D__BIONIC__ 
endif

# Define the versions containing the full options
APP_CXXFLAGS := $(APP_CXXFLAGS_NOOPT) $(APP_OPT_CXX) $(DBG_INFO_CXX)
APP_LDFLAGS := $(APP_LDFLAGS_NOOPT) $(APP_OPT_LD) $(DBG_INFO_LD)
# Pin tools should be compiled with conventional CRT flags:
# /MD or /MDd (use dynamic CRT release / debug versions).
# Link has to be done with corresponding set of CRT libs.
# Currently both TOOL_CXXFLAGS and SATOOL_CXXFLAFS use /MD* flags.
TOOL_CXXFLAGS := $(TOOL_CXXFLAGS_NOOPT) $(TOOL_OPT_CXX) $(DBG_INFO_CXX)
SATOOL_CXXFLAGS := $(TOOL_CXXFLAGS)
TOOL_CFLAGS := $(filter-out /GR-,$(TOOL_CXXFLAGS))
# Remove the below flags for icx-cl (Intel C compiler).
# The C compiler does not recognize these flags as opposed to Microsoft and clang-cl C compilers.
ifeq ($(COMPILER),icx)
	TOOL_CFLAGS := $(filter-out /EHs- /EHa- /wd4530 /Zc:threadSafeInit- /Zc:sizedDealloc- /wd5208 /nologo ,$(TOOL_CXXFLAGS))
endif
TOOL_LDFLAGS := $(TOOL_LDFLAGS_NOOPT) $(TOOL_OPT_LD) $(DBG_INFO_LD)
SATOOL_LDFLAGS := $(SATOOL_LDFLAGS_NOOPT) $(TOOL_OPT_LD) $(DBG_INFO_LD)
EXPORT_MAIN := /EXPORT:main
TOOL_LIBRARY_LDFLAGS_NOOPT := $(filter-out $(EXPORT_MAIN),$(TOOL_LDFLAGS_NOOPT))

# Add debugging flags to the NOOPT versions and disable optimizations
CXXFLAGS_DEBUG := $(OPT_CXX_DEBUG) $(DBG_INFO_CXX_ALWAYS)
LDFLAGS_DEBUG := $(OPT_LD_DEBUG) $(DBG_INFO_LD_ALWAYS)
APP_CXXFLAGS_NOOPT += $(CXXFLAGS_DEBUG)
APP_LDFLAGS_NOOPT += $(LDFLAGS_DEBUG)
TOOL_CXXFLAGS_NOOPT += $(CXXFLAGS_DEBUG)
SATOOL_CXXFLAGS_NOOPT := $(TOOL_CXXFLAGS_NOOPT)
TOOL_LDFLAGS_NOOPT += $(LDFLAGS_DEBUG)
SATOOL_LDFLAGS_NOOPT += $(LDFLAGS_DEBUG)

## Pin program finalization:

# Add any additional flags that the user specified to the Pin command line.
PIN += $(PIN_TESTFLAGS) $(PINFLAGS)

# Extracts the major and minor Windows version ID and build number (e.g. for XP 64 bit it's 5.2.3790 --> 5, 2, 3790)
WIN_VER_MAJOR := $(shell echo $(shell cmd /c ver) | cut -f 2 -d "[" | cut -f 2 -d " " | cut -f 1 -d .)
WIN_VER_MINOR := $(shell echo $(shell cmd /c ver) | cut -f 2 -d "[" | cut -f 2 -d " " | cut -f 2 -d .)
WIN_BUILD_NUMBER := $(shell echo $(shell cmd /c ver) | cut -f 2 -d "[" | cut -f 2 -d " " | cut -f 3 -d . | cut -f 1 -d "]")
export WIN_VER_MAJOR
export WIN_VER_MINOR
export WIN_BUILD_NUMBER

SET_DLL_PATH := export PATH=$(PIN_ROOT)/$(TARGET)/bin:$$PATH;
