#
# Copyright (C) 2012-2025 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.

SYS_NAME := =$(shell uname -s)
ifeq (CYGWIN, $(findstring CYGWIN, $(SYS_NAME)))
    SHELL_TYPE:=Cygwin
else ifeq (MINGW, $(findstring MINGW, $(SYS_NAME)))
    SHELL_TYPE:=Mingw
else ifeq (MSYS_NT, $(findstring MSYS_NT, $(SYS_NAME)))
    SHELL_TYPE:=Mingw
else
    $(error Invalid Windows build shell. Supported shells are Cygwin and Mingw based shells)
endif

ifeq (Mingw, $(SHELL_TYPE))
    override CMD := $(CMD_PREFIX) cmd //C
endif

## General flags

# If we are testing Pin, add some internal checks. Don't do this by default
# since it may incur a performance penalty.
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 :=
EXPORT := -EXPORT:
EXPORT_MAIN := -EXPORT:main

# 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, TOOL_INCLUDES and RPC_PLUGIN_INCLUDES are internal utilities for this file.
APP_INCLUDES :=
TOOL_INCLUDES :=
RPC_PLUGIN_INCLUDES :=

## Library paths

APP_LPATHS :=
TOOL_LPATHS :=
SATOOL_LPATHS :=

APP_LIBS :=
APP_LIB_XED := xed.lib

TOOL_LIBS := pin.lib pinrt-adaptor-static.lib xed.lib kernel32.lib
SATOOL_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_CFLAGS_NOOPT := -nologo -DTARGET_WINDOWS -DFUND_TC_HOSTOS=FUND_OS_WINDOWS \
                    -DFUND_TC_TARGETOS=FUND_OS_WINDOWS -Gy-
APP_CXXFLAGS_NOOPT := -EHa /std:c++17
ASM_FLAGS := -nologo -Cp
RPC_PLUGIN_CXXFLAGS_NOOPT := /DTARGET_WINDOWS /std:c++17 /Zc:__cplusplus /DEBUG

# clang-cl compiler requires those special flags
CLANG_CXXFLAGS := -Wno-non-c-typedef-for-linkage -Wno-microsoft-include -Wno-unicode


TOOL_CXXFLAGS_NOOPT := ${CLANG_CXXFLAGS}
DLL_CXXFLAGS :=
ENABLE_DEPRECATED := -DPIN_DEPRECATED_WARNINGS=0

# no additional flags are required to support Restricted Transactional Memory on clang-cl
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.
TOOL_LDFLAGS_NOOPT := -dll -c++ $(EXPORT_MAIN) -INCREMENTAL:NO -IGNORE:4210 -IGNORE:4049
# Assume options /DYNAMICBASE and /NXCOMPAT are accepted by all supported Windows linkers.
TOOL_LDFLAGS_NOOPT += -DYNAMICBASE -NXCOMPAT
SATOOL_LDFLAGS_NOOPT := -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 ######

# 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
ifeq (Cygwin, $(SHELL_TYPE))
    INJ_ROOT := $(shell cygpath -a -m $(PIN_ROOT))
else
    INJ_ROOT := $(realpath $(PIN_ROOT))
endif

# Since we change the CXX and LINKER we have to set APP_CC, APP_CXX and APP_LINKER earlier here.
# APP_CC and APP_CXX are defined here to make sure that the default on Windows is clang (regardless of
# what compiler is used to build the pintools), unless user set APP_CXX in shell, in which case
# these settings will not override the value set from the environment.
APP_CC ?= cl
APP_CXX ?= cl
APP_LINKER ?= link
APP_ARCHIVER := $(ARCHIVER)

# Set CXX and LINKER to pin wrappers
ifeq ($(COMPILER),icx)
    override CXX := $(PIN_ROOT)/$(TARGET)/pinrt/bin/pin-icx++
else
    override CXX := $(PIN_ROOT)/$(TARGET)/pinrt/bin/pin-clang-cl++
endif
override LINKER := $(PIN_ROOT)/$(TARGET)/pinrt/bin/pin-ld
override ARCHIVER := lib -LIBPATH:$(PIN_ROOT)/$(TARGET)/pinrt/lib -lib -out:

COMPONENT_INCLUDES := -I$(PIN_ROOT)/extras/components/include
TOOL_INCLUDES += -I$(PIN_ROOT)/source/include/pin \
                -I$(PIN_ROOT)/source/include/pin/gen \
                -I$(PIN_ROOT)/$(TARGET)/pinrt/include/adaptor


APP_LPATHS += -LIBPATH:$(PIN_ROOT)/extras/components/lib/$(TARGET) \
                -LIBPATH:$(XED_ROOT)/lib
TOOL_LPATHS += -LIBPATH:$(PIN_ROOT)/$(TARGET)/lib \
                -LIBPATH:$(XED_ROOT)/lib
SATOOL_LPATHS += -LIBPATH:$(PIN_ROOT)/$(TARGET)/lib \
                    -LIBPATH:$(XED_ROOT)/lib

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)
PIND := $(PIN_ROOT)/$(TARGET)/pinrt/bin/pind$(EXE_SUFFIX)
PIND32 := $(PIN_ROOT)/ia32/pinrt/bin/pind$(EXE_SUFFIX)
PIND64 := $(PIN_ROOT)/intel64/pinrt/bin/pind$(EXE_SUFFIX)

TOOL_INCLUDES += $(COMPONENT_INCLUDES) \
                -I$(XED_ROOT)/include/xed \
                -I$(TOOLS_ROOT)/Utils
RPC_PLUGIN_INCLUDES += /I$(PIN_ROOT)/$(TARGET)/pinrt/include/adaptor
APP_INCLUDES += -I$(TOOLS_ROOT)/Utils

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

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

ifeq ($(TARGET),ia32)
    APP_CFLAGS_NOOPT += -DTARGET_IA32 -DHOST_IA32 -DFUND_TC_TARGETCPU=FUND_CPU_IA32 -DFUND_TC_HOSTCPU=FUND_CPU_IA32
    ASM_FLAGS += -DTARGET_IA32
    SSE2 := /arch:SSE2
endif

ifeq ($(TARGET),intel64)
    APP_CFLAGS_NOOPT += -DTARGET_IA32E -DHOST_IA32E -DFUND_TC_TARGETCPU=FUND_CPU_INTEL64 -DFUND_TC_HOSTCPU=FUND_CPU_INTEL64
    ASM_FLAGS += -DTARGET_IA32E
    NO_ASLR := -HIGHENTROPYVA:NO
endif

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

## Compiler and linker flags

# Add the include paths to the compilation flags.
APP_CFLAGS_NOOPT += $(APP_INCLUDES)
TOOL_CXXFLAGS_NOOPT += $(TOOL_INCLUDES)
# RPC plugin flags is the same as app flags with addition of specific plugin include paths.
RPC_PLUGIN_CXXFLAGS_NOOPT += $(RPC_PLUGIN_INCLUDES)
# MASM supports only 10 include directories so we have to be very picky...
ASM_FLAGS += -I$(TOOLS_ROOT)/Utils

# Define the versions containing the full options
APP_CFLAGS := $(APP_CFLAGS_NOOPT) $(APP_OPT_CXX) $(DBG_INFO_CXX)
APP_CXXFLAGS_NOOPT += $(APP_CFLAGS_NOOPT)
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)

RPC_PLUGIN_CXXFLAGS := $(RPC_PLUGIN_CXXFLAGS_NOOPT) $(APP_OPT_CXX) $(DBG_INFO_CXX)
SATOOL_CXXFLAGS := $(TOOL_CXXFLAGS)
TOOL_CFLAGS := $(TOOL_CXXFLAGS)
TOOL_LDFLAGS := $(TOOL_LDFLAGS_NOOPT) $(TOOL_OPT_LD) $(DBG_INFO_LD)
SATOOL_LDFLAGS := $(SATOOL_LDFLAGS_NOOPT) $(TOOL_OPT_LD) $(DBG_INFO_LD)
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_CFLAGS_NOOPT += $(CXXFLAGS_DEBUG)
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)
RPC_PLUGIN_CXXFLAGS_NOOPT += $(CXXFLAGS_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;
