It seems like to clang, binary operator && is exactly the same as and - its alternative operator representation. In the ast, both end up as BinaryOperator [...] 'bool' '&&'. Is there a way to distinguish them nevertheless?
I was hoping to be able to retrieve the actual source code string but have not been able to do so yet.
I am trying to do this using clang-tidy while writing a check that suggests using and instead of &&. I looked at clang::ASTContext, but didn't find anything that would get me anywhere.
As you have discovered, the AST itself does not distinguish between the
two ways to spell the operator. However, the AST has source location
information that can be used to get the original text. The idea is to
use:
clang::BinaryOperator::getOperatorLoc()
to get the start location of the operator, then
clang::Lexer::getLocForEndOfToken()
to get its end location, then
clang::Lexer::getSourceText()
to get the operator text.
Note that when the operator results from a macro expansion, the source
retrieval method I am using does not work well, and I do not know if
that can be fixed.
Here is the core of a clang-tidy check that does what you want (except
for cases involving macros):
// https://stackoverflow.com/questions/11083066/getting-the-source-behind-clangs-ast
std::string get_source_text_raw(SourceRange range, SourceManager const &sm)
{
return std::string(
clang::Lexer::getSourceText(
clang::CharSourceRange::getCharRange(range), sm, clang::LangOptions()
)
);
}
void FindOpAnd::registerMatchers(ast_matchers::MatchFinder *Finder)
{
// Match use of operator '&&' or 'and'.
Finder->addMatcher(
binaryOperator(hasOperatorName("&&"))
.bind("op"), this);
}
void FindOpAnd::check(const MatchFinder::MatchResult &Result)
{
ASTContext &context = *(Result.Context);
SourceManager &sm = context.getSourceManager();
// Get the node bound to "op" in the match expression.
const auto *opExpr = Result.Nodes.getNodeAs<BinaryOperator>("op");
// Location of the start of the operator.
SourceLocation opLoc = opExpr->getOperatorLoc();
// Try to find the location of the end.
SourceLocation opEndLoc =
clang::Lexer::getLocForEndOfToken(opLoc, 0, sm, clang::LangOptions());
if (opEndLoc.isValid()) {
// Get the text of the operator.
SourceRange opRange(opLoc, opEndLoc);
std::string opText = get_source_text_raw(opRange, sm);
if (opText == "&&") {
diag(opLoc, "Using '&&' instead of 'and'.")
<< FixItHint::CreateReplacement(opRange, "and");
}
else if (opText == "and") {
// This what we want.
}
else {
// This happens when the operator itself is the result of a macro
// expansion.
}
}
else {
// The end location will not be found if the operator was inside
// the expansion of a macro.
}
}
Sample input:
// op-and.cc
// Test input for clang-tidy FindOpAnd checker.
// Note: There are no digraphs or trigraphs for '&', so that is not a
// concern here.
#define MY_AMPER_OPERATOR &&
#define MY_AND_OPERATOR and
#define MY_AMPER_EXPR(a,b) ((a) && (b))
#define MY_AND_EXPR(a,b) ((a) and (b))
void f(bool a, bool b)
{
bool r;
r = a && b; // Reported.
r = a and b; // Not reported.
// Not reported: Operator name not recognized.
r = a MY_AMPER_OPERATOR b;
r = a MY_AND_OPERATOR b;
// Not reported: Operator end location is invalid so we cannot get the
// operator name.
r = MY_AMPER_EXPR(a,b);
r = MY_AND_EXPR(a,b);
}
// EOF
Sample output:
$ ./FindOpAnd.exe -checks=-*,FindOpAnd in/op-and.cc \
--export-fixes=out/op-and.cc.fixes.yaml --
1 warning generated.
[...]/in/op-and.cc:17:9: warning: Using '&&' instead of 'and'. [FindOpAnd]
r = a && b; // Reported.
^~
and
To actually apply the suggested fixes, pass the --fix option.
For completeness, here is the full checker source and its Makefile:
// FindOpAnd.cc
// Code for FindOpAnd.h.
#include "FindOpAnd.h" // this module
#include "clang/AST/ASTContext.h" // ASTContext
#include "clang/Lex/Lexer.h" // clang::Lexer
#include "clang-tidy/ClangTidyModule.h" // ClangTidyModule
#include "clang-tidy/ClangTidyModuleRegistry.h" // ClangTidyModuleRegistry
using namespace clang::ast_matchers;
namespace clang {
namespace tidy {
// https://stackoverflow.com/questions/11083066/getting-the-source-behind-clangs-ast
std::string get_source_text_raw(SourceRange range, SourceManager const &sm)
{
return std::string(
clang::Lexer::getSourceText(
clang::CharSourceRange::getCharRange(range), sm, clang::LangOptions()
)
);
}
void FindOpAnd::registerMatchers(ast_matchers::MatchFinder *Finder)
{
// Match use of operator '&&' or 'and'.
Finder->addMatcher(
binaryOperator(hasOperatorName("&&"))
.bind("op"), this);
}
void FindOpAnd::check(const MatchFinder::MatchResult &Result)
{
ASTContext &context = *(Result.Context);
SourceManager &sm = context.getSourceManager();
// Get the node bound to "op" in the match expression.
const auto *opExpr = Result.Nodes.getNodeAs<BinaryOperator>("op");
// Location of the start of the operator.
SourceLocation opLoc = opExpr->getOperatorLoc();
// Try to find the location of the end.
SourceLocation opEndLoc =
clang::Lexer::getLocForEndOfToken(opLoc, 0, sm, clang::LangOptions());
if (opEndLoc.isValid()) {
// Get the text of the operator.
SourceRange opRange(opLoc, opEndLoc);
std::string opText = get_source_text_raw(opRange, sm);
if (opText == "&&") {
diag(opLoc, "Using '&&' instead of 'and'.")
<< FixItHint::CreateReplacement(opRange, "and");
}
else if (opText == "and") {
// This what we want.
}
else {
// This happens when the operator itself is the result of a macro
// expansion.
}
}
else {
// The end location will not be found if the operator was inside
// the expansion of a macro.
}
}
class FindOpAndModule : public ClangTidyModule {
public:
void addCheckFactories(ClangTidyCheckFactories &CheckFactories) override {
CheckFactories.registerCheck<FindOpAnd>("FindOpAnd");
}
};
static ClangTidyModuleRegistry::Add<FindOpAndModule> X(
"FindOpAndModule",
"Adds FindOpAnd check.");
// This is defined in libclangTidyMain.a. It does not appear to be
// declared in any header file, so I doubt this is really how it is
// meant to be used.
int clangTidyMain(int argc, const char **argv);
} // namespace tidy
} // namespace clang
int main(int argc, const char **argv)
{
return clang::tidy::clangTidyMain(argc, argv);
}
// EOF
// FindOpAnd.h
// clang-tidy check to find operator '&&' as opposed to 'and'.
#ifndef FIND_OP_AND_H
#define FIND_OP_AND_H
#include "clang-tidy/ClangTidyCheck.h" // ClangTidyCheck
#include "clang/ASTMatchers/ASTMatchFinder.h" // ast_matchers::MatchFinder
namespace clang {
namespace tidy {
class FindOpAnd : public ClangTidyCheck {
public:
FindOpAnd(StringRef Name, ClangTidyContext *Context)
: ClangTidyCheck(Name, Context) {}
void registerMatchers(ast_matchers::MatchFinder *Finder) override;
void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
};
} // namespace tidy
} // namespace clang
#endif // FIND_OP_AND_H
# clang-tidy-op-and/Makefile
# Default target.
all:
.PHONY: all
# Eliminate all implicit rules.
.SUFFIXES:
# Delete a target when its recipe fails.
.DELETE_ON_ERROR:
# Do not remove "intermediate" targets.
.SECONDARY:
# ---- Paths ----
# Installation directory from a binary distribution.
# Has five subdirectories: bin include lib libexec share.
# Downloaded from: https://github.com/llvm/llvm-project/releases/download/llvmorg-14.0.0/clang+llvm-14.0.0-x86_64-linux-gnu-ubuntu-18.04.tar.xz
CLANG_LLVM_INSTALL_DIR = $(HOME)/opt/clang+llvm-14.0.0-x86_64-linux-gnu-ubuntu-18.04
# Program to query the various LLVM configuration options.
LLVM_CONFIG = $(CLANG_LLVM_INSTALL_DIR)/bin/llvm-config
# ---- Compiler options ----
# C++ compiler.
CXX = g++
# Compiler options, including preprocessor options.
CXXFLAGS =
CXXFLAGS += -Wall
# Get llvm compilation flags.
CXXFLAGS += $(shell $(LLVM_CONFIG) --cxxflags)
# Linker options.
LDFLAGS =
# Needed libraries. The order is important. I do not know a principled
# way to obtain this list. I did it by chasing down each missing symbol
# in a link error.
LDFLAGS += -lclangTidy
LDFLAGS += -lclangTidyMain
LDFLAGS += -lclangTidyPlugin
LDFLAGS += -lclangToolingCore
LDFLAGS += -lclangFormat
LDFLAGS += -lclangToolingInclusions
LDFLAGS += -lclangTidyAbseilModule
LDFLAGS += -lclangTidyAlteraModule
LDFLAGS += -lclangTidyAndroidModule
LDFLAGS += -lclangTidyBoostModule
LDFLAGS += -lclangTidyBugproneModule
LDFLAGS += -lclangTidyCERTModule
LDFLAGS += -lclangTidyConcurrencyModule
LDFLAGS += -lclangTidyCppCoreGuidelinesModule
LDFLAGS += -lclangTidyDarwinModule
LDFLAGS += -lclangTidyFuchsiaModule
LDFLAGS += -lclangTidyGoogleModule
LDFLAGS += -lclangTidyHICPPModule
LDFLAGS += -lclangTidyLLVMLibcModule
LDFLAGS += -lclangTidyLLVMModule
LDFLAGS += -lclangTidyLinuxKernelModule
LDFLAGS += -lclangTidyMPIModule
LDFLAGS += -lclangTidyMiscModule
LDFLAGS += -lclangTidyModernizeModule
LDFLAGS += -lclangTidyObjCModule
LDFLAGS += -lclangTidyOpenMPModule
LDFLAGS += -lclangTidyPerformanceModule
LDFLAGS += -lclangTidyPortabilityModule
LDFLAGS += -lclangTidyReadabilityModule
LDFLAGS += -lclangTidyZirconModule
LDFLAGS += -lclangTidyUtils
LDFLAGS += -lclangTransformer
LDFLAGS += -lclangTooling
LDFLAGS += -lclangFrontendTool
LDFLAGS += -lclangFrontend
LDFLAGS += -lclangDriver
LDFLAGS += -lclangSerialization
LDFLAGS += -lclangCodeGen
LDFLAGS += -lclangParse
LDFLAGS += -lclangSema
LDFLAGS += -lclangStaticAnalyzerFrontend
LDFLAGS += -lclangStaticAnalyzerCheckers
LDFLAGS += -lclangStaticAnalyzerCore
LDFLAGS += -lclangAnalysis
LDFLAGS += -lclangARCMigrate
LDFLAGS += -lclangRewrite
LDFLAGS += -lclangRewriteFrontend
LDFLAGS += -lclangEdit
LDFLAGS += -lclangCrossTU
LDFLAGS += -lclangIndex
LDFLAGS += -lclangAST
LDFLAGS += -lclangASTMatchers
LDFLAGS += -lclangLex
LDFLAGS += -lclangBasic
LDFLAGS += -lclang
# *After* clang libs, the llvm libs.
LDFLAGS += $(shell $(LLVM_CONFIG) --ldflags --libs --system-libs)
# ---- Recipes ----
# Pull in automatic dependencies.
-include $(wildcard obj/*.d)
# Compile a C++ source file.
obj/%.o: %.cc
#mkdir -p $(dir $#)
$(CXX) -MMD -c -o $# $(USE_PCH) $< $(CXXFLAGS)
# Sources for 'FindOpAnd.exe'.
SRCS :=
SRCS += FindOpAnd.cc
# Objects for 'FindOpAnd.exe'.
OBJS := $(patsubst %.cc,obj/%.o,$(SRCS))
# Executable.
all: FindOpAnd.exe
FindOpAnd.exe: $(OBJS)
$(CXX) -g -Wall -o $# $(OBJS) $(LDFLAGS)
# Run program on one input.
out/%: in/% FindOpAnd.exe
#mkdir -p $(dir $#)
./FindOpAnd.exe -checks=-*,FindOpAnd in/$* \
--export-fixes=out/$*.fixes.yaml \
-- </dev/null 2>&1 | cat
touch $#
# Run tests.
.PHONY: check
check: FindOpAnd.exe
check: out/op-and.cc
# Remove test outputs.
.PHONY: check-clean
check-clean:
rm -rf out
# Remove compile and test outputs.
.PHONY: clean
clean: check-clean
$(RM) *.exe
rm -rf obj
# EOF
Related
I need to solve a nonlinear system of equations and I found the MINPACK library to do the job.
But I need the code to work with CUDA and I'm not able to compile the code.
I'm facing this problem:
nvcc -arch sm_61 -Iinc -I/usr/local/include obj/main.o -o oi -L/usr/local/lib64 -lcuminpack
nvlink error : Undefined reference to 'dpmpar' in 'obj/main.o'
make: *** [makefile:55: oi] Erro 255
My main file is:
main.cu
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#define __cminpack_double__
#include <cminpack-1/cminpack.h>
#define real __cminpack_real__
typedef struct{
real fnorm1, fnorm2;
int info;
real solution[2];
} ResultType;
__cminpack_attr__ int fcn(void *p, int n, const real *x, real *fvec, int iflag){
--fvec;
--x;
fvec[0] = x[0] + x[0]*x[1] - 4.0;
fvec[1] = x[0] + x[1] -3.0;
return 0;
}
__global__ void SolvingSystem(ResultType *pResults){
int info;
real fnorm1, fnorm2, tol;
int n = 2;
real fvec[2];
real x[2];
const int lwa = (n*(3*n + 13))/2;
real wa[50];
tol = sqrt(dpmpar(1));
x[0] = 1.98;
x[1] = 1.02;
printf("Initial Guess: %g, %g\n", x[0], x[1]);
}
int main(int argc, char const *argv[]){
cudaSetDevice(0);
ResultType *reuslt_GPU, *reuslt_CPU;
cudaMalloc((void**)&reuslt_GPU, sizeof(ResultType));
cudaMallocHost((void**)&reuslt_CPU, sizeof(ResultType));
printf("Solving System...\n");
dim3 grid(1, 1, 1);
dim3 block(1, 1, 1);
SolvingSystem<<< grid, block>>>(reuslt_GPU);
cudaDeviceSynchronize();
printf("Done!\n");
return 0;
}
And my makefile is:
makefile
# MakeFile
# Program Name
EXE = oi
# Compilers
NVCC := nvcc
ALL_LIBRARIES := cuminpack
LIBDIR := /usr/local/lib64
# Directories
SRCDIR := src
OBJDIR := obj
INCDIR := inc /usr/local/include
#Flags
NVCCARCHFLAG := -arch sm_61
NVCCFLAGS := -std=c++11
LDFLAGS := $(addprefix -L, $(LIBDIR))
INCLUDES := $(addprefix -I, $(INCDIR))
LIBRARIES := $(addprefix -l, $(ALL_LIBRARIES))
LIBRARIES +=
ALL_CPFLAGS := -MMD
ALL_CPFLAGS += $(NVCCARCHFLAG)
ALL_CPFLAGS += $(NVCCFLAGS)
ALL_LDFLAGS := $(LDFLAGS)
# Files
C_FILES := $(wildcard $(SRCDIR)/*.c)
CU_FILES := $(wildcard $(SRCDIR)/*.cu)
C_OBJ := $(patsubst $(SRCDIR)/%.c, $(OBJDIR)/%.o, $(C_FILES))
CU_OBJ := $(patsubst $(SRCDIR)/%.cu, $(OBJDIR)/%.o, $(CU_FILES))
C_DEP := $(patsubst $(SRCDIR)/%.c, $(OBJDIR)/%.d, $(C_FILES))
CU_DEP := $(patsubst $(SRCDIR)/%.cu, $(OBJDIR)/%.d, $(CU_FILES))
SRC := $(C_FILES) $(CU_FILES)
OBJ := $(C_OBJ) $(CU_OBJ)
DEP := $(C_DEP) $(CU_DEP)
COMPILE.c := $(NVCC) -MMD -g $(INCLUDES) -c
COMPILE.cu := $(NVCC) $(ALL_CPFLAGS) $(INCLUDES) -dc
.PHONY: all clean
all:$(EXE)
$(EXE): $(OBJ)
$(NVCC) $(NVCCARCHFLAG) $(INCLUDES) $^ -o $# $(ALL_LDFLAGS) $(LIBRARIES)
$(OBJDIR)/%.o: $(SRCDIR)/%.c | $(OBJDIR)
$(COMPILE.c) $< -o $#
$(OBJDIR)/%.o: $(SRCDIR)/%.cu | $(OBJDIR)
$(COMPILE.cu) $< -o $#
$(OBJDIR):
#mkdir -p $#
# Cleaning up
clean:
#echo Cleaning up...
#rm -f -r $(OBJDIR)
#rm $(EXE)
# Including dependency
-include $(DEP)
The main file needs to be finished and that's the reason to some unused variables.
I just can't figure out what is causing this error, I think the problem is in cuminpack library, but I don't now how to fix it.
I'm using cminpack-1.3.8 from this website: http://devernay.free.fr/hacks/cminpack/
I installed the library using cmake then make and make install. Then I went to source folder and did make cuda. This last command generated libcuminpack.a file in cuda directory, then I copied this .a file to /usr/local/lib64 where cmake installed the other libraries files.
If anyone could help me I would be very thankful
EDIT
Files from the cminpack library
cminpack.h
...
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
...
#if defined(__CUDA_ARCH__) || defined(__CUDACC__)
#define __cminpack_attr__ __device__
#ifndef __cminpack_real__
#define __cminpack_float__
#define __cminpack_real__ float
#endif
#define __cminpack_type_fcn_nn__ __cminpack_attr__ int fcn_nn
#define __cminpack_type_fcnder_nn__ __cminpack_attr__ int fcnder_nn
#define __cminpack_type_fcn_mn__ __cminpack_attr__ int fcn_mn
#define __cminpack_type_fcnder_mn__ __cminpack_attr__ int fcnder_mn
#define __cminpack_type_fcnderstr_mn__ __cminpack_attr__ int fcnderstr_mn
#define __cminpack_decl_fcn_nn__
#define __cminpack_decl_fcnder_nn__
#define __cminpack_decl_fcn_mn__
#define __cminpack_decl_fcnder_mn__
#define __cminpack_decl_fcnderstr_mn__
#define __cminpack_param_fcn_nn__
#define __cminpack_param_fcnder_nn__
#define __cminpack_param_fcn_mn__
#define __cminpack_param_fcnder_mn__
#define __cminpack_param_fcnderstr_mn__
...
__cminpack_attr__
__cminpack_real__ CMINPACK_EXPORT __cminpack_func__(dpmpar)( int i );
dpmpar.c
#include "cminpack.h"
#include <float.h>
#include "cminpackP.h"
#define DPMPAR(type,X) _DPMPAR(type,X)
#define _DPMPAR(type,X) type ## _ ## X
__cminpack_attr__
real __cminpack_func__(dpmpar)(int i)
{
/* ********** */
/* Function dpmpar */
...
Based on talonmies's comment I was able to compile the code defining the __device__ function dpmpar in main.cu file.
Then I found this post https://forums.developer.nvidia.com/t/external-calls-to-device-functions/17737 where the guy answered that CUDA doesn't have a linker on the device side, so it's not possible to call a __device__ function from a different .cu file.
With this in mind, I copied only the files that I needed from the library and made some modifications, like changing __cminpack_attr__ to __device__ and I rewrote the header file too. So basically I made my own device library (thank's again to talonmies's).
The last thing I did was move all this new files to the same folder where my main.cu and my makefile lives and I rewrote the makefile.
Now the code compile fine!!
Alright, new user here, and I've got a problem. I'm a new c++ student, and I have no prior experience in this language (before about 3 months ago). My assignment is as follows:
Write a program that declares an array darray of 50 elements of type double. Initialize the array so that the first 25 elements are equal to the square of the index variable, and the last 25 elements are equal to three times the index variable. Output the array so that 10 elements per line are printed.
The program should have two functions: a function, initArray(), which initializes the array elements, and a function, prArray(), which prints the elements.
I have that, it's as follows
#include "printArray.h"
#include "initializearray.h"
#include "Main.h"
#include <stdio.h>
#include <iostream>
#include <string>
using namespace std;
double initArray();
double prArray(double arrayone[50]);
double * dArray;
int main() {
dArray[50] = initArray();
system("PAUSE");
prArray(dArray);
system("PAUSE");
return 0;
}
#include "printArray.h"
#include "initializearray.h"
#include "Main.h"
#include <iostream>
#include <string>
using namespace std;
double prArray(double arraytwo[50])
{
for (int x = 0; x < 50; x++) {
cout << arraytwo[x];
if (x = 9 || 19 || 29 || 39 || 49) {
cout << endl;
}
}
return 0;
}
#include "printArray.h"
#include "initializearray.h"
#include "Main.h"
#include <iostream>
#include <string>
int x = 0;
double arrayone[50];
double initArray()
{
for (x = 0; x < 25; x++) {
arrayone[x] = (x*x);
}
for (x = 25; x <= 50; x++) {
arrayone[x] = (x * 3);
}
return arrayone[50];
}
Now my problem is that the assignment goes on to say
Write a Makefile to compile the program above that minimizes recompiling items upon changes. (e.g., if one function file gets updated, only the necessary file(s) are recompiled.) Include a clean target that removes compiled objects if invoked.
I have a basic makefile:
CC=g++
CFLAGS=-c -Wall
LDFLAGS=
SOURCES=Main.cpp initializeArray.cpp printArray.cpp
OBJECTS=$(SOURCES:.cpp=.o)
EXECUTABLE=Main
all: $(SOURCES) $(EXECUTABLE)
$(EXECUTABLE): $(OBJECTS)
$(CC) $(LDFLAGS) $(OBJECTS) -o $#
.cpp.o:
$(CC) $(CFLAGS) $< -o $#
Now, what I need help with is turning this into a makefile that satisfies the assignment conditions - preferably with step-by-step instructions so that I can learn from this.
Modified your Makefile to:
Automatically generate header dependencies.
Re-build and re-link when Makefile changes.
CXX := g++
LD := ${CXX}
CXXFLAGS := -Wall -Wextra -std=gnu++14 -pthread
LDFLAGS := -pthread
exes :=
# Specify EXEs here begin.
Main.SOURCES := Main.cpp initializeArray.cpp printArray.cpp
exes += Main
# Specify EXEs here end.
all: $(exes)
.SECONDEXPANSION:
get_objects = $(patsubst %.cpp,%.o,${${1}.SOURCES})
get_deps = $(patsubst %.cpp,%.d,${${1}.SOURCES})
# Links executables.
${exes} : % : $$(call get_objects,$$*) Makefile
${LD} -o $# $(filter-out Makefile,$^) ${LDFLAGS}
# Compiles C++ and generates dependencies.
%.o : %.cpp Makefile
${CXX} -o $# -c ${CPPFLAGS} ${CXXFLAGS} -MP -MD $<
# Include the dependencies generated on a previous build.
-include $(foreach exe,${exes},$(call get_deps,${exe}))
.PHONY: all
I'm developing a QT widget that makes use of SIMD instruction sets. I've compiled 3 versions: SSE3, AVX, and AVX2(simdpp allows to switch between them by a single #define).
Now, what I want is for my widget to switch automatically between these implementations, according to best supported instruction set. Guide that is provided with simdpp makes use of some makefile magic:
CXXFLAGS=""
test: main.o test_sse2.o test_sse3.o test_sse4_1.o test_null.o
g++ $^ -o test
main.o: main.cc
g++ main.cc $(CXXFLAGS) -c -o main.o
test_null.o: test.cc
g++ test.cc -c $(CXXFLAGS) -DSIMDPP_EMIT_DISPATCHER \
-DSIMDPP_DISPATCH_ARCH1=SIMDPP_ARCH_X86_SSE2 \
-DSIMDPP_DISPATCH_ARCH2=SIMDPP_ARCH_X86_SSE3 \
-DSIMDPP_DISPATCH_ARCH3=SIMDPP_ARCH_X86_SSE4_1 -o test_null.o
test_sse2.o: test.cc
g++ test.cc -c $(CXXFLAGS) -DSIMDPP_ARCH_X86_SSE2 -msse2 -o test_sse2.o
test_sse3.o: test.cc
g++ test.cc -c $(CXXFLAGS) -DSIMDPP_ARCH_X86_SSE3 -msse3 -o test_sse3.o
test_sse4_1.o: test.cc
g++ test.cc -c $(CXXFLAGS) -DSIMDPP_ARCH_X86_SSE4_1 -msse4.1 -o test_sse4_1.o
Here is a link to the guide: http://p12tic.github.io/libsimdpp/v2.0~rc2/libsimdpp/arch/dispatch.html
I have no idea how to implement such behavior with qmake. Any ideas?
First that comes to mind is to create a shared library with dispatched code, and link it to the project. Here I'm stuck again. App is cross-platform, which means it has to compile with both GCC and MSVC(vc120, to be exact), which forces using nmake in Windows, and I tried, really, but it was like the worst experience in my whole programmer life.
Thanks in advance, programmers of the world!
sorry if this is a bit late. Hope I can still help.
You need to consider 2 areas: Compile time and run time.
Compile time - need to create code to support different features.
Run time - need to create code to decide which features you can run.
What you are wanting to do is create a dispatcher...
FuncImpl.h:
#pragma once
void execAvx2();
void execAvx();
void execSse();
void execDefault();
FuncImpl.cpp:
// Compile this file once for each variant with different compiler settings.
#if defined(__AVX2__)
void execAvx2()
{
// AVX2 impl
...
}
#elif defined (__AVX__)
void execAvx()
{
// AVX impl
...
}
#elif defined (__SSE4_2__)
void execSse()
{
// Sse impl
...
}
#else
void execDefault()
{
// Vanilla impl
...
}
#endif
DispatchFunc.cpp
#include "FuncImpl.h"
// Decide at runtime which code to run
void dispatchFunc()
{
if(CheckCpuAvx2Flag())
{
execAvx2();
}
else if(CheckCpuAvxFlag())
{
execAvx();
}
else if(CheckCpuSseFlags())
{
execSse();
}
else
{
execDefault();
}
}
What you can do is create a set of QMAKE_EXTRA_COMPILERS.
SampleCompiler.pri (Do this for each variant):
MyCompiler.name = MyCompiler # Name
MyCompiler.input = MY_SOURCES # Symbol of the source list to compile
MyCompiler.dependency_type = TYPE_C
MyCompiler.variable_out = OBJECTS
# EXTRA_CXXFLAGS = -mavx / -mavx2 / -msse4.2
# _var = creates FileName_var.o => replace with own variant (_sse, etc)
MyCompiler.output = ${QMAKE_VAR_OBJECTS_DIR}${QMAKE_FILE_IN_BASE}_var$${first(QMAKE_EXT_OBJ)}
MyCompiler.commands = $${QMAKE_CXX} $(CXXFLAGS) $${EXTRA_CXXFLAGS} $(INCPATH) -c ${QMAKE_FILE_IN} -o${QMAKE_FILE_OUT}
QMAKE_EXTRA_COMPILERS += MyCompiler # Add my compiler
MyProject.pro
...
include(SseCompiler.pri)
include(AvxCompiler.pri)
include(Avx2Compiler.pri)
..
# Normal sources
# Will create FuncImpl.o and DispatchFunc.o
SOURCES += FuncImpl.cpp \
DispatchFunc.cpp
# Give the other compilers their sources
# Will create FuncImpl_avx2.o FuncImpl_avx.o FuncImpl_sse.o
AVX2_SOURCES += FuncImpl.cpp
AVX_SOURCES += FuncImpl.cpp
SSE_SOURCES += FuncImpl.cpp
# Link all objects
...
All you need now is to call dispatchFunc()!
Checking cpu flags is another exercise for you:
cpuid
These are just project defines. You set them with DEFINES += in your .pro file.You set the flags for the instructions sets you want to support and simdpp takes care of selecting the best one for the processor at runtime.
See for example, Add a define to qmake WITH a value?
Here is a qmake .pro file for use with SIMD dispatchers. It is quite verbose, so for more instruction sets, it is better to generate the dispatched blocks by a script, write it to a .pri file and then include it from your main .pro file.
TEMPLATE = app
TARGET = simd_test
INCLUDEPATH += .
QMAKE_CXXFLAGS = -O3 -std=c++17
SOURCES += main.cpp
SOURCES_dispatch = test.cpp
{
# SSE2
DISPATCH_CXXFLAGS = -msse2
DISPATCH_SUFFIX = _sse2
src_dispatch_sse2.name = src_dispatch_sse2
src_dispatch_sse2.input = SOURCES_dispatch
src_dispatch_sse2.dependency_type = TYPE_C
src_dispatch_sse2.variable_out = OBJECTS
src_dispatch_sse2.output = ${QMAKE_VAR_OBJECTS_DIR}${QMAKE_FILE_IN_BASE}$${DISPATCH_SUFFIX}$${first(QMAKE_EXT_OBJ)}
src_dispatch_sse2.commands = $${QMAKE_CXX} $(CXXFLAGS) $${DISPATCH_CXXFLAGS} $(INCPATH) -c ${QMAKE_FILE_IN} -o ${QMAKE_FILE_OUT}
QMAKE_EXTRA_COMPILERS += src_dispatch_sse2
}
{
# SSE3
DISPATCH_CXXFLAGS = -msse3
DISPATCH_SUFFIX = _sse3
src_dispatch_sse3.name = src_dispatch_sse3
src_dispatch_sse3.input = SOURCES_dispatch
src_dispatch_sse3.dependency_type = TYPE_C
src_dispatch_sse3.variable_out = OBJECTS
src_dispatch_sse3.output = ${QMAKE_VAR_OBJECTS_DIR}${QMAKE_FILE_IN_BASE}$${DISPATCH_SUFFIX}$${first(QMAKE_EXT_OBJ)}
src_dispatch_sse3.commands = $${QMAKE_CXX} $(CXXFLAGS) $${DISPATCH_CXXFLAGS} $(INCPATH) -c ${QMAKE_FILE_IN} -o ${QMAKE_FILE_OUT}
QMAKE_EXTRA_COMPILERS += src_dispatch_sse3
}
{
# SSE41
DISPATCH_CXXFLAGS = -msse4.1
DISPATCH_SUFFIX = _sse41
src_dispatch_sse41.name = src_dispatch_sse41
src_dispatch_sse41.input = SOURCES_dispatch
src_dispatch_sse41.dependency_type = TYPE_C
src_dispatch_sse41.variable_out = OBJECTS
src_dispatch_sse41.output = ${QMAKE_VAR_OBJECTS_DIR}${QMAKE_FILE_IN_BASE}$${DISPATCH_SUFFIX}$${first(QMAKE_EXT_OBJ)}
src_dispatch_sse41.commands = $${QMAKE_CXX} $(CXXFLAGS) $${DISPATCH_CXXFLAGS} $(INCPATH) -c ${QMAKE_FILE_IN} -o ${QMAKE_FILE_OUT}
QMAKE_EXTRA_COMPILERS += src_dispatch_sse41
}
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 6 years ago.
Improve this question
I have problem in compelling my code. The error message indicates "missing template arguments" in Map.h. But I do believe there is not any error in Map.h, because it is from Minisat, which is a sophistic API. So I think it is my fault in code or in makefile. I have tried so many times, can you help me on this? Thank you so much!
The error message is:
Compiling: queryOrac/queryOrac.o
In file included from /home/parallels/Desktop/Incremental_Solver/core/SolverTypes.h:30:0,
from /home/parallels/Desktop/Incremental_Solver/core/Solver.h:28,
from /home/parallels/Desktop/Incremental_Solver/simp/SimpSolver.h:25,
from /home/parallels/Desktop/Incremental_Solver/queryOrac/queryOrac.cc:12:
/home/parallels/Desktop/Incremental_Solver/mtl/Map.h: In member function ‘uint32_t Minisat::Hash<K>::operator()(const K&) const’:
/home/parallels/Desktop/Incremental_Solver/mtl/Map.h:32:99: error: missing template arguments before ‘(’ token
template<class K> struct Hash { uint32_t operator()(const K& k) const { return hash(k); } };
^
/home/parallels/Desktop/Incremental_Solver/mtl/Map.h: In member function ‘uint32_t Minisat::DeepHash<K>::operator()(const K*) const’:
/home/parallels/Desktop/Incremental_Solver/mtl/Map.h:35:103: error: missing template arguments before ‘(’ token
template<class K> struct DeepHash { uint32_t operator()(const K* k) const { return hash(*k); } };
^
make: *** [/home/parallels/Desktop/Incremental_Solver/queryOrac/queryOrac.o] Error 1
The .cc file is (This file is a implementation of a .h file):
#include <map>
#include <string>
#include <vector>
#include <sstream>
#include <fstream>
#include <iostream>
#include <regex>
#include "queryOrac/queryOrac.h"
#include "incre/tools.h"
#include "incre/dict.h"
#include "simp/SimpSolver.h"
#include "utils/System.h"
#include "utils/ParseUtils.h"
#include "utils/Options.h"
#include "core/Dimacs.h"
using namespace std;
using namespace Minisat;
using namespace Incre;
Oracle::Oracle(const char * ora, const char * PI, const char * PO)
{
cout << "a Oracle is created" << endl;
PI_path = PI;
PO_path = PO;
Orac_Path = ora;
}
void Oracle::process()
{
parse_PI();
assign_PI();
solve();
}
void Oracle::parse_PI() {
cout << "reading from " << PI_path << endl;
ifstream infile;
infile.open(PI_path, ios::in);
string first_line;
string second_line;
getline(infile, first_line);
getline(infile, second_line);
vector<string> name_temp;
vector<string> value_temp;
SplitString(first_line, name_temp, " ");
SplitString(second_line, value_temp, " ");
vector<string>::iterator value = value_temp.begin();
for(vector<string>::iterator name = name_temp.begin(); name != name_temp.end(); ++name)
{
PI_temp.insert(pair<int, string>(varIndexDict[*name], *value));
value++;
}
}
void Oracle::assign_PI(){
vector<int>::iterator position = pisIndex.begin();
for(map<int, string>::iterator index = PI_temp.begin(); index != PI_temp.end(); ++index)
{
if(index->second == "1") PI_assignment_cnf.push_back(tostring(*position) + " 0\n");
else if(index->second == "0") PI_assignment_cnf.push_back("-" + tostring(*position) + " 0\n");
position++;
}
PI_assignment_cnf.insert(PI_assignment_cnf.begin(), "c this is assign_PI\n");
cnFile += PI_assignment_cnf;
print_vector(cnFile, "cnFile");
}
void Oracle::solve(){
cout << " start solving" << endl;
}
my makefile is:
##
## Template makefile for Standard, Profile, Debug, Release, and Release-static versions
##
## eg: "make rs" for a statically linked release version.
## "make d" for a debug version (no optimizations).
## "make" for the standard version (optimized, but with debug information and assertions active)
PWD = $(shell pwd)
EXEC ?= $(notdir $(PWD))
CSRCS = $(wildcard $(PWD)/*.cc)
DSRCS = $(foreach dir, $(DEPDIR), $(filter-out $(MROOT)/$(dir)/Main.cc, $(wildcard $(MROOT)/$(dir)/*.cc)))
CHDRS = $(wildcard $(PWD)/*.h)
COBJS = $(CSRCS:.cc=.o) $(DSRCS:.cc=.o)
PCOBJS = $(addsuffix p, $(COBJS))
DCOBJS = $(addsuffix d, $(COBJS))
RCOBJS = $(addsuffix r, $(COBJS))
CXX ?= g++
CFLAGS ?= -Wall -Wno-parentheses -std=c++11
LFLAGS ?= -Wall
COPTIMIZE ?= -O3
CFLAGS += -I$(MROOT) -D __STDC_LIMIT_MACROS -D __STDC_FORMAT_MACROS
LFLAGS += -lz
.PHONY : s p d r rs clean
s: $(EXEC)
p: $(EXEC)_profile
d: $(EXEC)_debug
r: $(EXEC)_release
rs: $(EXEC)_static
libs: lib$(LIB)_standard.a
libp: lib$(LIB)_profile.a
libd: lib$(LIB)_debug.a
libr: lib$(LIB)_release.a
## Compile options
%.o: CFLAGS +=$(COPTIMIZE) -g -D DEBUG
%.op: CFLAGS +=$(COPTIMIZE) -pg -g -D NDEBUG
%.od: CFLAGS +=-O0 -g -D DEBUG
%.or: CFLAGS +=$(COPTIMIZE) -g -D NDEBUG
## Link options
$(EXEC): LFLAGS += -g
$(EXEC)_profile: LFLAGS += -g -pg
$(EXEC)_debug: LFLAGS += -g
#$(EXEC)_release: LFLAGS += ...
$(EXEC)_static: LFLAGS += --static
## Dependencies
$(EXEC): $(COBJS)
$(EXEC)_profile: $(PCOBJS)
$(EXEC)_debug: $(DCOBJS)
$(EXEC)_release: $(RCOBJS)
$(EXEC)_static: $(RCOBJS)
lib$(LIB)_standard.a: $(filter-out */Main.o, $(COBJS))
lib$(LIB)_profile.a: $(filter-out */Main.op, $(PCOBJS))
lib$(LIB)_debug.a: $(filter-out */Main.od, $(DCOBJS))
lib$(LIB)_release.a: $(filter-out */Main.or, $(RCOBJS))
## Build rule
%.o %.op %.od %.or: %.cc
#echo Compiling: $(subst $(MROOT)/,,$#)
#$(CXX) $(CFLAGS) -c -o $# $<
## Linking rules (standard/profile/debug/release)
$(EXEC) $(EXEC)_profile $(EXEC)_debug $(EXEC)_release $(EXEC)_static:
#echo Linking: "$# ( $(foreach f,$^,$(subst $(MROOT)/,,$f)) )"
#$(CXX) $^ $(LFLAGS) -o $#
## Library rules (standard/profile/debug/release)
lib$(LIB)_standard.a lib$(LIB)_profile.a lib$(LIB)_release.a lib$(LIB)_debug.a:
#echo Making library: "$# ( $(foreach f,$^,$(subst $(MROOT)/,,$f)) )"
#$(AR) -rcsv $# $^
## Library Soft Link rule:
libs libp libd libr:
#echo "Making Soft Link: $^ -> lib$(LIB).a"
#ln -sf $^ lib$(LIB).a
## Clean rule
clean:
#rm -f $(EXEC) $(EXEC)_profile $(EXEC)_debug $(EXEC)_release $(EXEC)_static \
$(COBJS) $(PCOBJS) $(DCOBJS) $(RCOBJS) *.core depend.mk
## Make dependencies
depend.mk: $(CSRCS) $(CHDRS)
#echo Making dependencies
#$(CXX) $(CFLAGS) -I$(MROOT) \
$(CSRCS) -MM | sed 's|\(.*\):|$(PWD)/\1 $(PWD)/\1r $(PWD)/\1d $(PWD)/\1p:|' > depend.mk
#for dir in $(DEPDIR); do \
if [ -r $(MROOT)/$${dir}/depend.mk ]; then \
echo Depends on: $${dir}; \
cat $(MROOT)/$${dir}/depend.mk >> depend.mk; \
fi; \
done
-include $(MROOT)/mtl/config.mk
-include depend.mk
Your problem is due to using namespace std;. Don't do that, ever.
Some people say it's fine as long as it's not in a header file, but they are wrong, and your error is a great example.
In this case, you're accidentally referring to std::hash, which is a class template, so the <> cannot be omitted, unlike for function templates.
C++ How do i run makefile output
Below is my MakeFile, I want to ask how do i run my unitTest.cpp, as because when i MakeFile with NetBean, using the MakeFile below, main.exe is actually the main.cpp output
BUT I want to run the output of unitTest.cpp
How do i run unitTest.cpp
# ExampleTests Project
SRCS = main.cpp currencyConverter.cpp unitTest.cpp
HDRS = currencyConverter.h unitTest.h
PROJ = main
# Remaining lines shouldn't need changing
# Here's what they do:
# - rebuild if any header file or this Makefile changes
# - include CppUnit as dynamic library
# - search /opt/local for MacPorts
# - generate .exe files for Windows
# - add -enable-auto-import flag for Cygwin only
CC = g++
OBJS = $(SRCS:.cpp=.o)
APP = $(PROJ).exe
CFLAGS = -c -g -Wall -I/opt/local/include
ifeq (,$(findstring CYGWIN,$(shell uname)))
LDFLAGS = -L/opt/local/lib
else
LDFLAGS = -L/opt/local/lib -enable-auto-import
endif
LIBS = -lcppunit -ldl
all: $(APP)
$(APP): $(OBJS)
$(CC) $(LDFLAGS) $(OBJS) -o $(APP) $(LIBS)
%.o: %.cpp $(HDRS)
$(CC) $(CFLAGS) $< -o $#
clean:
rm -f *.o $(APP)
Below is my unitTest.cpp
#include "unitTest.h"
#include "currencyConverter.h"
CPPUNIT_TEST_SUITE_REGISTRATION(unitTest);
unitTest::unitTest() {
}
unitTest::~unitTest() {
}
void unitTest::setUp() {
}
void unitTest::tearDown() {
}
void stringToUpper(string&);
void unitTest::testStringLowerToUpper()
{
string str = "ILOVECPLUSPLUS";
string str2 = "IloveCplusplus";
cout << "\nChecking if string 1 '" << str << "' equals string 2 '" << str2 << "'";
CPPUNIT_ASSERT_EQUAL(str,str2);
//this part i will use my stringToUpperFunction to test.
currencyConverter c;
c.stringToUpper(str2);
cout << "\nChecking if string 1 '" << str << "' equals string 2 '" << str2 << "'";
CPPUNIT_ASSERT_EQUAL(str,str2);
}
Add another target (e.g. testrunner.exe) dependent on the .cpp files you want to test + your testsuite .cpp files + another .cpp file that consitutes the main() for your testrunner application to your make file. Having this you can add another target test, dependent on testrunner.exe that just calls the testrunner.exe executable.