    def gen_makefile(self, file_pairs, dll_name, workdir, test_name, debug_settings):
        makefile_template = jinja2.Template(
            """
CC = {{cc}}
CFLAGS = {{CFLAGS}}
fPIC_flag = {{fPIC}}

obj_files = {{obj_files}}

%.obj : %.{{cpp}}
    {{cfile_cmd}}
%.obj : %.bin
    {{bfile_cmd}}

.PHONY: all clean clean_constants
all: {{targets}}

{{dll_target}}: $(obj_files)
    {{build_so_cmd}}

{{build_standalone_rules}}

clean:
    rm -f *.obj {{targets}}

clean_constants:
    rm -f constants.bin
"""
        )

        standalone_rules_template = jinja2.Template(
            """
{{standalone_src}}: {{standalone_obj}}
    {{cfile_cmd}}

{{exe_target}}: {{exe_target_deps}}
    {{build_exe_cmd}}
"""
        )

        build_so_cmd = "$(CC) -shared $(fPIC_flag) $(CFLAGS) -o $@ $(obj_files)"
        standalone_src = "standalone.cu"
        standalone_obj = "standalone.obj"
        windll_obj = "windll.obj"
        obj_files = []
        # * standalone.cu is an AITemplate internal file that is used for generating
        #   standalone executables. We only want to compile it when the relevant
        #   debug option is enabled.
        # * windll.cu and windll.obj are used in builder_cmake.py for MSVC compiler
        #   and are not needed to be used in builder_make.py compiler engine.
        obj_files = [
            pair[1].split("/")[-1]
            for pair in file_pairs
            if not pair[1].endswith(standalone_obj) and not pair[1].endswith(windll_obj)
        ]
        obj_files = " ".join(obj_files)

        cc = Target.current().cc()
        compile_options = Target.current().compile_options()

        fpic, cpp = "-fPIC", "cpp"
        if "nvcc" in cc:
            fpic, cpp = "-Xcompiler=-fPIC", "cu"

        cfile_cmd = Target.current().compile_cmd(False).format(target="$@", src="$<")
        bfile_cmd = Target.current().binary_compile_cmd()

        if not bfile_cmd:
            bfile_cmd = ""
        else:
            bfile_cmd = bfile_cmd.format(target="$@", src="$<")

        if self._do_trace:
            cfile_cmd = _augment_for_trace(cfile_cmd)
            bfile_cmd = _augment_for_trace(bfile_cmd)
            build_so_cmd = _augment_for_trace(build_so_cmd)
        else:
            cfile_cmd = _time_cmd(cfile_cmd)
            bfile_cmd = _time_cmd(bfile_cmd)
            build_so_cmd = _time_cmd(build_so_cmd)

        build_exe_cmd = _time_cmd("$(CC) $(CFLAGS) -o $@ $(obj_files)")
        targets = f"{dll_name}"

        build_standalone_rules = ""
        if debug_settings.gen_standalone:
            build_exe_cmd = f"$(CC) $(CFLAGS) -o $@ {standalone_obj} {dll_name}"
            exe_name = os.path.splitext(dll_name)[0]
            if is_windows():
                exe_name += ".exe"
            exe_target_deps = f"{dll_name} {standalone_obj}"
            build_standalone_rules = standalone_rules_template.render(
                standalone_src=standalone_src,
                standalone_obj=standalone_obj,
                cfile_cmd=cfile_cmd,
                exe_target=exe_name,
                exe_target_deps=exe_target_deps,
                build_exe_cmd=build_exe_cmd,
            )
            targets += f" {exe_name}"

        makefile_str = makefile_template.render(
            cc=cc,
            cpp=cpp,
            CFLAGS=compile_options,
            fPIC=fpic,
            obj_files=obj_files,
            dll_target=dll_name,
            targets=targets,
            cfile_cmd=cfile_cmd,
            bfile_cmd=bfile_cmd,
            build_so_cmd=build_so_cmd,
            build_standalone_rules=build_standalone_rules,
        )

        dumpfile = os.path.join(workdir, test_name, "Makefile")
        with open(dumpfile, "w+") as f:
            # fix the makefile indentation
            f.write(re.sub("^    ", "\t", makefile_str, flags=re.M))
CC = {{cc}}
CFLAGS = {{CFLAGS}}
fPIC_flag = {{fPIC}}

obj_files = {{obj_files}}

%.obj : %.{{cpp}}
{{cfile_cmd}}
%.obj : %.bin
{{bfile_cmd}}

.PHONY: all clean clean_constants
all: {{targets}}

{{dll_target}}: $(obj_files)
{{build_so_cmd}}

{{build_standalone_rules}}

clean:
rm -f *.obj {{targets}}

clean_constants:
rm -f constants.bin
python/aitemplate/backend/builder.py