Skip to content

Commit d046796

Browse files
authored
Overhaul top-level Makefile (#791)
1 parent 4cc73d0 commit d046796

3 files changed

Lines changed: 209 additions & 71 deletions

File tree

Makefile

Lines changed: 103 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,93 @@
1+
# Copyright 2025 Google LLC
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# https://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
# Version info for the copy of Eigen we will download and build locally.
116
EIGEN_PREFIX = "3bb6a48d8c171cf20b5f8e48bfb4e424fbd4f79e"
217
EIGEN_URL = "https://gitlab.com/libeigen/eigen/-/archive/"
318

19+
# Default build targets. Additional may be added conditionally below.
420
TARGETS = qsim
521
TESTS = run-cxx-tests
622

7-
CXX=g++
8-
NVCC=nvcc
9-
HIPCC=hipcc
23+
# By default, we also build the pybind11-based Python interface.
24+
PYBIND11 ?= true
1025

11-
CXXFLAGS = -O3 -fopenmp
12-
ARCHFLAGS = -march=native
13-
NVCCFLAGS = -O3
14-
HIPCCFLAGS = -O3
26+
ifeq ($(PYBIND11), true)
27+
TARGETS += pybind
28+
TESTS += run-py-tests
29+
endif
1530

16-
# CUQUANTUM_ROOT should be set.
17-
CUSTATEVECFLAGS = -I$(CUQUANTUM_ROOT)/include -L${CUQUANTUM_ROOT}/lib -L$(CUQUANTUM_ROOT)/lib64 -lcustatevec -lcublas
31+
# Default options for Pytest (only used if the pybind interface is built).
32+
PYTESTFLAGS ?= -v
33+
34+
# Default C++ compilers and compiler flags. Can be overriden via env variables.
35+
CXX ?= g++
36+
NVCC ?= nvcc
37+
HIPCC ?= hipcc
38+
39+
CXXFLAGS ?= -O3 -std=c++17 -fopenmp
40+
NVCCFLAGS ?= -O3 --std c++17 -Wno-deprecated-gpu-targets
41+
HIPCCFLAGS ?= -O3
42+
43+
# Determine whether we can include CUDA and cuStateVec support. We build for
44+
# CUDA if (i) we find $NVCC or (ii) $CUDA_PATH is set. For cuStateVec, there's
45+
# no way to find the cuQuantum libraries other than by being told, so we rely
46+
# on the user or calling environment to set variable $CUQUANTUM_ROOT.
47+
48+
ifneq (,$(shell which $(NVCC)))
49+
# nvcc adds appropriate -I and -L flags, so nothing more is needed here.
50+
TARGETS += qsim-cuda
51+
TESTS += run-cuda-tests
52+
else
53+
ifneq (,$(strip $(CUDA_PATH)))
54+
# $CUDA_PATH is set. Check that the path truly does exist.
55+
ifneq (,$(strip $(wildcard $(CUDA_PATH)/.)))
56+
# $CUDA_PATH is set, but we know we didn't find nvcc on the user's
57+
# $PATH or as an absolute path (if $NVCC was set to a full path).
58+
# Try the safest choice for finding nvcc & give up if that fails.
59+
NVCC = $(CUDA_PATH)/bin/nvcc
60+
ifneq (,$(strip $(wildcard $(NVCC))))
61+
CXXFLAGS += -I$(CUDA_PATH)/include -L$(CUDA_PATH)/lib64
62+
TARGETS += qsim-cuda
63+
TESTS += run-cuda-tests
64+
else
65+
$(warning nvcc not found, so cannot build CUDA interfaces)
66+
endif
67+
else
68+
$(warning $$CUDA_PATH is set, but the path does not seem to exist)
69+
endif
70+
endif
71+
endif
1872

19-
PYBIND11 = true
73+
ifneq (,$(strip $(CUQUANTUM_ROOT)))
74+
# $CUQUANTUM_ROOT is set. Check that the path truly does exist.
75+
ifneq (,$(strip $(wildcard $(CUQUANTUM_ROOT)/.)))
76+
CUSVFLAGS = -I$(CUQUANTUM_ROOT)/include
77+
CUSVFLAGS += -L${CUQUANTUM_ROOT}/lib -L$(CUQUANTUM_ROOT)/lib64
78+
CUSVFLAGS += -lcustatevec -lcublas
79+
CUSTATEVECFLAGS ?= $(CUSVFLAGS)
80+
TARGETS += qsim-custatevec
81+
TESTS += run-custatevec-tests
82+
else
83+
$(warning $$CUQUANTUM_ROOT is set, but the path does not seem to exist)
84+
endif
85+
endif
2086

21-
export CXX
22-
export CXXFLAGS
23-
export ARCHFLAGS
24-
export NVCC
25-
export NVCCFLAGS
26-
export CUSTATEVECFLAGS
27-
export HIPCC
28-
export HIPCCFLAGS
87+
# Export all variables to subprocesses without having to export them individually.
88+
.EXPORT_ALL_VARIABLES:
2989

30-
ifeq ($(PYBIND11), true)
31-
TARGETS += pybind
32-
TESTS += run-py-tests
33-
endif
90+
# The rest is build rules and make targets.
3491

3592
.PHONY: all
3693
all: $(TARGETS)
@@ -44,7 +101,7 @@ qsim-cuda:
44101
$(MAKE) -C apps/ qsim-cuda
45102

46103
.PHONY: qsim-custatevec
47-
qsim-custatevec:
104+
qsim-custatevec: | check-cuquantum-root-set
48105
$(MAKE) -C apps/ qsim-custatevec
49106

50107
.PHONY: qsim-hip
@@ -64,7 +121,7 @@ cuda-tests:
64121
$(MAKE) -C tests/ cuda-tests
65122

66123
.PHONY: custatevec-tests
67-
custatevec-tests:
124+
custatevec-tests: | check-cuquantum-root-set
68125
$(MAKE) -C tests/ custatevec-tests
69126

70127
.PHONY: hip-tests
@@ -87,25 +144,37 @@ run-custatevec-tests: custatevec-tests
87144
run-hip-tests: hip-tests
88145
$(MAKE) -C tests/ run-hip-tests
89146

90-
PYTESTS = $(shell find qsimcirq_tests/ -name '*_test.py')
147+
PYTESTS := $(wildcard qsimcirq_tests/*_test.py)
91148

92149
.PHONY: run-py-tests
93150
run-py-tests: pybind
94-
for exe in $(PYTESTS); do if ! python3 -m pytest $$exe; then exit 1; fi; done
151+
python3 -m pytest $(PYTESTFLAGS) $(PYTESTS)
152+
153+
.PHONY: run-tests tests
154+
run-tests tests: $(TESTS)
95155

96-
.PHONY: run-tests
97-
run-tests: $(TESTS)
156+
.PHONY: check-cuquantum-root-set
157+
check-cuquantum-root-set:
158+
@if [[ -z "$(CUQUANTUM_ROOT)" ]]; then \
159+
echo Error: '$$CUQUANTUM_ROOT must be set in order to use cuStateVec.' \
160+
exit 1 \
161+
fi
98162

99163
eigen:
100-
$(shell\
101-
rm -rf eigen;\
102-
wget $(EIGEN_URL)/$(EIGEN_PREFIX)/eigen-$(EIGEN_PREFIX).tar.gz;\
103-
tar -xf eigen-$(EIGEN_PREFIX).tar.gz && mv eigen-$(EIGEN_PREFIX) eigen;\
104-
rm eigen-$(EIGEN_PREFIX).tar.gz;)
164+
-rm -rf eigen
165+
wget $(EIGEN_URL)/$(EIGEN_PREFIX)/eigen-$(EIGEN_PREFIX).tar.gz
166+
tar -xzf eigen-$(EIGEN_PREFIX).tar.gz && mv eigen-$(EIGEN_PREFIX) eigen
167+
rm eigen-$(EIGEN_PREFIX).tar.gz
105168

106169
.PHONY: clean
107170
clean:
108-
rm -rf eigen;
171+
-rm -rf eigen
109172
-$(MAKE) -C apps/ clean
110173
-$(MAKE) -C tests/ clean
111174
-$(MAKE) -C pybind_interface/ clean
175+
176+
LOCAL_VARS = TARGETS TESTS PYTESTS PYTESTFLAGS CXX CXXFLAGS NVCC NVCCFLAGS $\
177+
HIPCC HIPCCFLAGS CUDA_PATH CUQUANTUM_ROOT CUSTATEVECFLAGS
178+
179+
.PHONY: print-vars
180+
print-vars: ; @$(foreach n,$(sort $(LOCAL_VARS)),echo $n=$($n);)

pybind_interface/Makefile

Lines changed: 44 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,57 @@
1+
# Copyright 2025 Google LLC
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# https://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
SUFFIX := $(shell python3-config --extension-suffix)
16+
117
# The names of the shared libraries that result after compiling qsim for Pybind11
2-
QSIMLIB_BASIC = ../qsimcirq/qsim_basic`python3-config --extension-suffix`
3-
QSIMLIB_SSE = ../qsimcirq/qsim_sse`python3-config --extension-suffix`
4-
QSIMLIB_AVX2 = ../qsimcirq/qsim_avx2`python3-config --extension-suffix`
5-
QSIMLIB_AVX512 = ../qsimcirq/qsim_avx512`python3-config --extension-suffix`
6-
QSIMLIB_CUDA = ../qsimcirq/qsim_cuda`python3-config --extension-suffix`
7-
QSIMLIB_CUSTATEVEC = ../qsimcirq/qsim_custatevec`python3-config --extension-suffix`
8-
QSIMLIB_HIP = ../qsimcirq/qsim_hip`python3-config --extension-suffix`
9-
QSIMLIB_DECIDE = ../qsimcirq/qsim_decide`python3-config --extension-suffix`
18+
QSIMLIB_BASIC = ../qsimcirq/qsim_basic$(SUFFIX)
19+
QSIMLIB_SSE = ../qsimcirq/qsim_sse$(SUFFIX)
20+
QSIMLIB_AVX2 = ../qsimcirq/qsim_avx2$(SUFFIX)
21+
QSIMLIB_AVX512 = ../qsimcirq/qsim_avx512$(SUFFIX)
22+
QSIMLIB_CUDA = ../qsimcirq/qsim_cuda$(SUFFIX)
23+
QSIMLIB_CUSTATEVEC = ../qsimcirq/qsim_custatevec$(SUFFIX)
24+
QSIMLIB_HIP = ../qsimcirq/qsim_hip$(SUFFIX)
25+
QSIMLIB_DECIDE = ../qsimcirq/qsim_decide$(SUFFIX)
26+
27+
# Certain Pybind11 flags are common for all cases.
28+
PYBIND_INCLUDES := $(shell pybind11-config --includes)
29+
PYBINDFLAGS = -Wall -shared -std=c++17 -fPIC $(PYBIND_INCLUDES)
30+
31+
# GCC 12 produces false-positive array-bounds warnings in some code (see
32+
# https://gcc.gnu.org/bugzilla/show_bug.cgi?id=115824). Pybind 3.x automatically
33+
# disables them (see https://github.com/pybind/pybind11/pull/5355/files). We're
34+
# still using 2.x, so we get the warnings unless we disable them ourselves.
35+
# TODO(mhucka): remove this once we can upgrade to Pybind11 version 3.x.
36+
GCC_MAJOR_VERSION := $(firstword $(subst ., ,$(shell gcc -dumpversion)))
37+
ifeq ($(GCC_MAJOR_VERSION), 12)
38+
PYBINDFLAGS += -Wno-array-bounds -Wno-stringop-overread
39+
endif
1040

1141
# The flags for the compilation of the simd-specific Pybind11 interfaces
12-
PYBINDFLAGS_BASIC = -Wall -shared -std=c++17 -fPIC `pybind11-config --includes`
13-
PYBINDFLAGS_SSE = -msse4.1 -Wall -shared -std=c++17 -fPIC `pybind11-config --includes`
14-
PYBINDFLAGS_AVX2 = -mavx2 -mfma -Wall -shared -std=c++17 -fPIC `pybind11-config --includes`
15-
PYBINDFLAGS_AVX512 = -mavx512f -mbmi2 -Wall -shared -std=c++17 -fPIC `pybind11-config --includes`
42+
PYBINDFLAGS_BASIC = $(PYBINDFLAGS)
43+
PYBINDFLAGS_SSE = -msse4.1 $(PYBINDFLAGS)
44+
PYBINDFLAGS_AVX2 = -mavx2 -mfma $(PYBINDFLAGS)
45+
PYBINDFLAGS_AVX512 = -mavx512f -mbmi2 $(PYBINDFLAGS)
1646

1747
# The flags for the compilation of CUDA-specific Pybind11 interfaces
18-
PYBINDFLAGS_CUDA = -std=c++17 -x cu -Xcompiler "-Wall -shared -fPIC `pybind11-config --includes`"
48+
PYBINDFLAGS_CUDA = -std=c++17 -x cu -Xcompiler "-Wall -shared -fPIC $(PYBIND_INCLUDES)"
1949

2050
# The flags for the compilation of cuStateVec-specific Pybind11 interfaces
2151
PYBINDFLAGS_CUSTATEVEC = $(CUSTATEVECFLAGS) $(PYBINDFLAGS_CUDA)
2252

2353
# The flags for the compilation of HIP-specific Pybind11 interfaces
24-
PYBINDFLAGS_HIP = -std=c++17 -Wall -shared -fPIC `pybind11-config --includes`
54+
PYBINDFLAGS_HIP = -std=c++17 -Wall -shared -fPIC $(PYBIND_INCLUDES)
2555

2656
# Check for nvcc to decide compilation mode.
2757
ifeq ($(shell which $(NVCC)),)

tests/Makefile

Lines changed: 62 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,62 @@
1-
HAVE_AVX512 = $(shell grep avx512f /proc/cpuinfo)
2-
CXX_TARGETS = $(shell\
3-
if [ -z "$(HAVE_AVX512)" ] ; then\
4-
find . -maxdepth 1 -name "*_test.cc" ! -name "*512*";\
5-
else\
6-
find . -maxdepth 1 -name "*_test.cc";\
7-
fi\
8-
)
9-
CXX_TARGETS := $(CXX_TARGETS:%.cc=%.x)
10-
11-
CUDA_TARGETS = $(shell find . -maxdepth 1 -name "*cuda_test.cu")
12-
CUDA_TARGETS := $(CUDA_TARGETS:%cuda_test.cu=%cuda_test.x)
13-
14-
CUSTATEVEC_TARGETS = $(shell find . -maxdepth 1 -name "*custatevec_test.cu")
15-
CUSTATEVEC_TARGETS := $(CUSTATEVEC_TARGETS:%custatevec_test.cu=%custatevec_test.x)
16-
17-
HIP_TARGETS = $(shell find . -maxdepth 1 -name "*cuda_test.cu")
18-
HIP_TARGETS := $(HIP_TARGETS:%cuda_test.cu=%hip_test.x)
19-
20-
GTEST_DIR = $(CURDIR)/googletest/googletest
21-
GMOCK_DIR = $(CURDIR)/googletest/googlemock
22-
23-
CMAKE=cmake
1+
# Copyright 2025 Google LLC
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# https://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
# Determine the hardware features available in this CPU.
16+
HAVE_SSE := $(shell grep -q sse /proc/cpuinfo && echo "true")
17+
HAVE_AVX2 := $(shell grep -q avx2 /proc/cpuinfo && echo "true")
18+
HAVE_AVX512 := $(shell grep -q avx512f /proc/cpuinfo && echo "true")
19+
20+
# Default targets. Always built.
21+
BASIC_FILES := $(shell ls *.cc | egrep -v '_avx|_sse')
22+
23+
# Additional flags and targets for non-CUDA cases.
24+
SSE_FILES =
25+
AVX2_FILES =
26+
AVX512_FILES =
27+
ifneq (,$(HAVE_SSE))
28+
SSE_FLAGS ?= -msse4.1
29+
SSE_FILES := $(wildcard *_sse_test.cc)
30+
endif
31+
ifneq (,$(HAVE_AVX2))
32+
AVX2_FLAGS ?= -mavx2 -mfma
33+
AVX2_FILES := $(wildcard *_avx_test.cc)
34+
endif
35+
ifneq (,$(HAVE_AVX512))
36+
AVX512_FLAGS ?= -mavx512f -mbmi2
37+
AVX512_FILES := $(wildcard *_avx512_test.cc)
38+
endif
39+
40+
CXX_FILES := $(BASIC_FILES) $(SSE_FILES) $(AVX2_FILES) $(AVX512_FILES)
41+
CXX_TARGETS := $(CXX_FILES:%.cc=%.x)
42+
CXXFLAGS := $(CXXFLAGS) $(SSE_FLAGS) $(AVX2_FLAGS) $(AVX512_FLAGS)
43+
44+
CUDA_FILES := $(wildcard *cuda_test.cu)
45+
CUDA_TARGETS := $(CUDA_FILES:%cuda_test.cu=%cuda_test.x)
46+
47+
CUSTATEVEC_FILES := $(wildcard *custatevec_test.cu)
48+
CUSTATEVEC_TARGETS := $(CUSTATEVEC_FILES:%custatevec_test.cu=%custatevec_test.x)
49+
50+
HIP_FILES := $(wildcard *cuda_test.cu)
51+
HIP_TARGETS := $(HIP_FILES:%cuda_test.cu=%hip_test.x)
52+
53+
GTEST_DIR := $(CURDIR)/googletest/googletest
54+
GMOCK_DIR := $(CURDIR)/googletest/googlemock
2455

2556
TESTFLAGS = -I$(GTEST_DIR)/include -L$(GTEST_DIR)/build/lib -lgtest
2657

58+
CMAKE = cmake
59+
2760
.PHONY: cxx-tests
2861
cxx-tests: $(CXX_TARGETS)
2962

@@ -74,3 +107,9 @@ $(GTEST_DIR)/build:
74107
clean:
75108
-rm -f ./*.x ./*.a ./*.so ./*.mod
76109
rm -rf $(GTEST_DIR)/build
110+
111+
LOCAL_VARS = HAVE_SSE HAVE_AVX2 HAVE_AVX512 SSE_FLAGS AVX2_FLAGS $\
112+
AVX512_FLAGS CXXFLAGS CXX_TARGETS TEST_FLAGS
113+
114+
.PHONY: print-vars
115+
print-vars: ; @$(foreach n,$(sort $(LOCAL_VARS)),echo $n=$($n);)

0 commit comments

Comments
 (0)