Repository: IITH-Compilers/IR2Vec (language: python)

Issue:
pip package to support python environment 
create a pip package to use the library exposed by IR2Vec in a python environment 


Discussion / hints:

Fix patch:
diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json
new file mode 100644
index 00000000..3c280588
--- /dev/null
+++ b/.devcontainer/devcontainer.json
@@ -0,0 +1,22 @@
+// For format details, see https://aka.ms/devcontainer.json. For config options, see the
+// README at: https://github.com/devcontainers/templates/tree/main/src/ubuntu
+{
+	"name": "LLVM Manylinux",
+	// Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile
+	"image": "ghcr.io/necessary129/manylinux2014-llvm:12-x86_64"
+
+	// Features to add to the dev container. More info: https://containers.dev/features.
+	// "features": {},
+
+	// Use 'forwardPorts' to make a list of ports inside the container available locally.
+	// "forwardPorts": [],
+
+	// Use 'postCreateCommand' to run commands after the container is created.
+	// "postCreateCommand": "uname -a",
+
+	// Configure tool-specific properties.
+	// "customizations": {},
+
+	// Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root.
+	// "remoteUser": "root"
+}
diff --git a/.github/workflows/upload-pypi.yml b/.github/workflows/upload-pypi.yml
new file mode 100644
index 00000000..4dc46370
--- /dev/null
+++ b/.github/workflows/upload-pypi.yml
@@ -0,0 +1,59 @@
+name: Upload to PyPI
+
+on:
+  release:
+    types:
+      - published
+  workflow_dispatch:
+    inputs:
+      pypi_repo:
+        description: 'Repo to upload to (testpypi or pypi)'
+        default: 'testpypi'
+        required: true
+        type: choice
+        options:
+          - testpypi
+          - pypi
+
+jobs:
+  build_wheels:
+    uses: ./.github/workflows/wheel.yml
+
+
+  build_sdist:
+    runs-on: ubuntu-latest
+    container: ghcr.io/necessary129/manylinux2014-llvm:12-x86_64
+    steps:
+      - uses: actions/checkout@v3
+
+      - name: Build IR2Vec
+        run: bash Manylinux2014_Compliant_Source/pkg/build.sh
+
+      - name: Build sdist
+        run: cd Manylinux2014_Compliant_Source/pkg && pipx run build --sdist
+
+      - uses: actions/upload-artifact@v3
+        with:
+          path: Manylinux2014_Compliant_Source/pkg/dist/*.tar.gz
+
+
+  upload_pypi:
+    permissions:
+      id-token: write
+    needs: [build_wheels, build_sdist]
+    runs-on: ubuntu-latest
+    steps:
+      - uses: actions/download-artifact@v3
+        with:
+          name: artifact
+          path: dist
+
+      - name: Publish package to TestPyPI
+        uses: pypa/gh-action-pypi-publish@v1.8.5
+        with:
+          repository-url: https://test.pypi.org/legacy/
+        if: ${{ github.event.inputs.pypi_repo != 'pypi' }}
+
+      - name: Publish package to PyPI
+        uses: pypa/gh-action-pypi-publish@v1.8.5
+        if: ${{ github.event.inputs.pypi_repo == 'pypi' }}
diff --git a/.github/workflows/wheel.yml b/.github/workflows/wheel.yml
new file mode 100644
index 00000000..ad446275
--- /dev/null
+++ b/.github/workflows/wheel.yml
@@ -0,0 +1,30 @@
+name: Build wheels
+
+on: [push, workflow_dispatch, workflow_call]
+
+jobs:
+  build_wheels:
+    name: Build wheels on ${{ matrix.os }}
+    runs-on: ${{ matrix.os }}
+    strategy:
+      matrix:
+        os: [ubuntu-20.04]
+
+    steps:
+      - uses: actions/checkout@v3
+
+      - name: Build wheels
+        uses: pypa/cibuildwheel@v2.13.1
+        with:
+          package-dir: Manylinux2014_Compliant_Source/pkg
+        env:
+          CIBW_SKIP: "pp* *-musllinux_*"
+          CIBW_ARCHS: "x86_64"
+          CIBW_MANYLINUX_X86_64_IMAGE: "ghcr.io/necessary129/manylinux2014-llvm:12-x86_64"
+          CIBW_BEFORE_ALL: "bash Manylinux2014_Compliant_Source/pkg/build.sh"
+          CIBW_TEST_REQUIRES: pytest
+          CIBW_TEST_COMMAND: "pytest {project}/Manylinux2014_Compliant_Source/pkg/tests"
+
+      - uses: actions/upload-artifact@v3
+        with:
+          path: ./wheelhouse/*.whl
diff --git a/.gitignore b/.gitignore
index 2fa33929..e38fa620 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,3 +3,4 @@ build/
 __pycache__/
 .vscode
 experiments/*/output
+.cache/
diff --git a/IR2Vec_Wheels/Python310/IR2Vec_pkg-1.0.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl b/IR2Vec_Wheels/Python310/IR2Vec_pkg-1.0.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
deleted file mode 100644
index b88f296a..00000000
Binary files a/IR2Vec_Wheels/Python310/IR2Vec_pkg-1.0.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl and /dev/null differ
diff --git a/IR2Vec_Wheels/Python311/IR2Vec_pkg-1.0.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl b/IR2Vec_Wheels/Python311/IR2Vec_pkg-1.0.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
deleted file mode 100644
index 7ac6791f..00000000
Binary files a/IR2Vec_Wheels/Python311/IR2Vec_pkg-1.0.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl and /dev/null differ
diff --git a/IR2Vec_Wheels/Python36/IR2Vec_pkg-1.0.0-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl b/IR2Vec_Wheels/Python36/IR2Vec_pkg-1.0.0-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
deleted file mode 100644
index 82004c03..00000000
Binary files a/IR2Vec_Wheels/Python36/IR2Vec_pkg-1.0.0-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl and /dev/null differ
diff --git a/IR2Vec_Wheels/Python37/IR2Vec_pkg-1.0.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl b/IR2Vec_Wheels/Python37/IR2Vec_pkg-1.0.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
deleted file mode 100644
index 0bf29a2f..00000000
Binary files a/IR2Vec_Wheels/Python37/IR2Vec_pkg-1.0.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl and /dev/null differ
diff --git a/IR2Vec_Wheels/Python38/IR2Vec_pkg-1.0.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl b/IR2Vec_Wheels/Python38/IR2Vec_pkg-1.0.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
deleted file mode 100644
index 94957871..00000000
Binary files a/IR2Vec_Wheels/Python38/IR2Vec_pkg-1.0.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl and /dev/null differ
diff --git a/IR2Vec_Wheels/Python39/IR2Vec_pkg-1.0.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl b/IR2Vec_Wheels/Python39/IR2Vec_pkg-1.0.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
deleted file mode 100644
index 50cb3bc3..00000000
Binary files a/IR2Vec_Wheels/Python39/IR2Vec_pkg-1.0.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl and /dev/null differ
diff --git a/Manylinux2014_Compliant_Source/.gitignore b/Manylinux2014_Compliant_Source/.gitignore
new file mode 100644
index 00000000..8a7b2a56
--- /dev/null
+++ b/Manylinux2014_Compliant_Source/.gitignore
@@ -0,0 +1,1 @@
+manylinux2014-LLVM/
diff --git a/Manylinux2014_Compliant_Source/manylinux-llvm/Dockerfile b/Manylinux2014_Compliant_Source/manylinux-llvm/Dockerfile
new file mode 100644
index 00000000..1f9de480
--- /dev/null
+++ b/Manylinux2014_Compliant_Source/manylinux-llvm/Dockerfile
@@ -0,0 +1,62 @@
+FROM quay.io/pypa/manylinux2014_x86_64 as builder
+LABEL maintainer="Shamil K (noteness@riseup.net)"
+
+RUN yum -y install cmake wget openssl-devel
+
+RUN mkdir /root/destdir
+
+WORKDIR /root/cmake
+ARG CMAKE_VERSION="3.26.4"
+RUN wget -q "https://github.com/Kitware/CMake/releases/download/v${CMAKE_VERSION}/cmake-${CMAKE_VERSION}.tar.gz" \
+	&& tar -xf "cmake-${CMAKE_VERSION}.tar.gz"
+WORKDIR "/root/cmake/cmake-${CMAKE_VERSION}"
+RUN cmake -DCMAKE_BUILD_TYPE=Release . \
+	&& make -j "$(nproc)" \
+	&& cmake --install . \
+	&& cmake --install . --prefix /root/destdir
+
+WORKDIR /root/ninja
+ARG NINJA_VERSION="1.11.1"
+RUN wget -q "https://github.com/ninja-build/ninja/archive/refs/tags/v${NINJA_VERSION}.tar.gz" \
+	&& tar -xf "v${NINJA_VERSION}.tar.gz"
+WORKDIR "/root/ninja/ninja-${NINJA_VERSION}"
+RUN cmake -DCMAKE_BUILD_TYPE=Release -B build \
+	&& cmake --build build -j"$(nproc)" \
+	&& cmake --install build \
+	&& cmake --install build --prefix /root/destdir
+
+WORKDIR /root/mold
+ARG MOLD_VERSION="1.11.0"
+RUN wget -q "https://github.com/rui314/mold/archive/refs/tags/v${MOLD_VERSION}.tar.gz" \
+	&& tar -xf "v${MOLD_VERSION}.tar.gz"
+WORKDIR "/root/mold/mold-${MOLD_VERSION}"
+RUN cmake -DCMAKE_BUILD_TYPE=Release -G Ninja -B build \
+	&& cmake --build build -j"$(nproc)" \
+	&& cmake --install build \
+	&& cmake --install build --prefix /root/destdir
+
+WORKDIR /root/llvm
+ARG LLVM_VERSION="12.0.1"
+RUN wget -q "https://github.com/llvm/llvm-project/releases/download/llvmorg-${LLVM_VERSION}/llvm-project-${LLVM_VERSION}.src.tar.xz" \
+	&& tar -xf "llvm-project-${LLVM_VERSION}.src.tar.xz"
+WORKDIR /root/llvm/llvm-project-${LLVM_VERSION}.src/build
+RUN cmake -G Ninja -DCMAKE_BUILD_TYPE=Release \
+	-DLLVM_ENABLE_PROJECTS='clang' \
+	-DCLANG_ENABLE_BOOTSTRAP=On \
+	-DLLVM_LINK_LLVM_DYLIB=On \
+	-DLLVM_USE_SPLIT_DWARF=On \
+	-DBOOTSTRAP_LLVM_LINK_LLVM_DYLIB=On \
+	-DBOOTSTRAP_LLVM_USE_SPLIT_DWARF=On \
+	-DBOOTSTRAP_LLVM_USE_LINKER=mold \
+	-DCMAKE_INSTALL_PREFIX=/root/destdir \
+	../llvm \
+	&& ninja stage2 \
+	&& ninja stage2-install
+
+FROM quay.io/pypa/manylinux2014_x86_64
+COPY --from=builder /root/destdir /usr/local/
+
+COPY entrypoint /usr/local/bin/entrypoint
+
+ENTRYPOINT ["entrypoint"]
+CMD ["/bin/bash"]
diff --git a/Manylinux2014_Compliant_Source/manylinux-llvm/entrypoint b/Manylinux2014_Compliant_Source/manylinux-llvm/entrypoint
new file mode 100755
index 00000000..2faa7592
--- /dev/null
+++ b/Manylinux2014_Compliant_Source/manylinux-llvm/entrypoint
@@ -0,0 +1,5 @@
+#!/bin/bash
+
+set -eu
+
+exec "$@"
diff --git a/Manylinux2014_Compliant_Source/pkg/IR2Vec/.gitignore b/Manylinux2014_Compliant_Source/pkg/IR2Vec/.gitignore
new file mode 100644
index 00000000..f1e5012b
--- /dev/null
+++ b/Manylinux2014_Compliant_Source/pkg/IR2Vec/.gitignore
@@ -0,0 +1,1 @@
+utils.h
diff --git a/Manylinux2014_Compliant_Source/pkg/IR2Vec/README.md b/Manylinux2014_Compliant_Source/pkg/IR2Vec/README.md
new file mode 100644
index 00000000..5bb2c0ac
--- /dev/null
+++ b/Manylinux2014_Compliant_Source/pkg/IR2Vec/README.md
@@ -0,0 +1,1 @@
+given input .ll/.bc generates corresponding IR2Vec embeddings in a file or on stdout
diff --git a/Manylinux2014_Compliant_Source/pkg/IR2Vec_pkg/__init__.py b/Manylinux2014_Compliant_Source/pkg/IR2Vec/__init__.py
similarity index 85%
rename from Manylinux2014_Compliant_Source/pkg/IR2Vec_pkg/__init__.py
rename to Manylinux2014_Compliant_Source/pkg/IR2Vec/__init__.py
index d468d99f..0bb4d8ee 100755
--- a/Manylinux2014_Compliant_Source/pkg/IR2Vec_pkg/__init__.py
+++ b/Manylinux2014_Compliant_Source/pkg/IR2Vec/__init__.py
@@ -1,5 +1,5 @@
 ### we have to find package before importing it else export LD_Lib path and LIB_path will not work.
 from . import preparation
-from IR2Vec_pkg.core import *
+from IR2Vec.core import *
 
 setSeedEmbdPath(preparation.install_loc_pkg)
diff --git a/Manylinux2014_Compliant_Source/pkg/IR2Vec_pkg/core.cpp b/Manylinux2014_Compliant_Source/pkg/IR2Vec/core.cpp
similarity index 93%
rename from Manylinux2014_Compliant_Source/pkg/IR2Vec_pkg/core.cpp
rename to Manylinux2014_Compliant_Source/pkg/IR2Vec/core.cpp
index 22b6dd43..0062f584 100644
--- a/Manylinux2014_Compliant_Source/pkg/IR2Vec_pkg/core.cpp
+++ b/Manylinux2014_Compliant_Source/pkg/IR2Vec/core.cpp
@@ -75,7 +75,6 @@ PyObject *set_seed_embedding_path(PyObject *self, PyObject *args) {
     seed_emb_path = string(vocab_path2);
   }
 
-  cout << seed_emb_path;
   return PyUnicode_FromString("Seed Embedding Path is Set");
 }
 
@@ -227,17 +226,12 @@ PyObject *IR2Vec_generateEmbeddings(PyObject *self, PyObject *args) {
     // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using cout to dump the output
     // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
     else {
-      IR2Vec::Embeddings Emb(*M, m, vocab_path, level[0], &cout);
+      IR2Vec::Embeddings Emb(*M, m, vocab_path, level[0], nullptr);
       llvm_inst_vec_map = Emb.getInstVecMap();
       llvm_func_vec_map = Emb.getFunctionVecMap();
       llvm_pgm_vec = Emb.getProgramVector();
     }
 
-    cout << endl << endl;
-    cout << "------------------------------------------------------------------"
-            "--"
-         << endl;
-
     // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ copying data from LLVM ADT's to C++
     // Containers ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ now make a python
     // dictionary that will hold 2 SmallMapVector and 1  SmallVector . But first
@@ -245,10 +239,10 @@ PyObject *IR2Vec_generateEmbeddings(PyObject *self, PyObject *args) {
     // containers
 
     vector<double> temp2;
-    const char *readable_name = "";
+    char *readable_name;
     string demangledName;
-    size_t sz;
-    int status;
+    size_t sz = 17;
+    int status = 0;
     // coying llvm samll map vector data into c++ map
 
     // for InstVecMap
@@ -266,7 +260,7 @@ PyObject *IR2Vec_generateEmbeddings(PyObject *self, PyObject *args) {
         readable_name =
             __cxxabiv1::__cxa_demangle(instName.c_str(), 0, &sz, &status);
         demangledName = status == 0 ? std::string(readable_name) : instName;
-        cout << demangledName << endl;
+        free(readable_name);
         InstVecMap[demangledName] = temp2;
       } else // if Value does not has a name
       {
@@ -293,13 +287,8 @@ PyObject *IR2Vec_generateEmbeddings(PyObject *self, PyObject *args) {
       for (auto &Vec_it : Func_it.second)
         temp2.push_back(Vec_it);
 
-      auto temp1 = Func_it.first->getName(); // getName returns StringRef
       // apply __cxx::demangle just to be cautious
-      auto funcName = temp1.str();
-      readable_name =
-          __cxxabiv1::__cxa_demangle(funcName.c_str(), 0, &sz, &status);
-      demangledName = status == 0 ? std::string(readable_name) : funcName;
-      cout << demangledName << endl;
+      demangledName = IR2Vec::getDemagledName(Func_it.first);
       FuncVecMap[demangledName] = temp2;
 
       temp2.clear();
@@ -319,10 +308,8 @@ PyObject *IR2Vec_generateEmbeddings(PyObject *self, PyObject *args) {
 
     for (auto Map_it1 : InstVecMap) {
       PyObject *temp3 = PyList_New(0);
-      cout << Map_it1.first << endl;
       for (auto &List_it1 : Map_it1.second)
         PyList_Append(temp3, PyFloat_FromDouble(List_it1));
-      // cout<<PyList_Size(temp3)<<endl;
       PyDict_SetDefault(InstVecDict,
                         PyUnicode_FromString((Map_it1.first).c_str()), Py_None);
       PyDict_SetItemString(InstVecDict, Map_it1.first.c_str(), temp3);
@@ -333,10 +320,8 @@ PyObject *IR2Vec_generateEmbeddings(PyObject *self, PyObject *args) {
     }
     for (auto Map_it1 : FuncVecMap) {
       PyObject *temp3 = PyList_New(0);
-      cout << Map_it1.first << endl;
       for (auto &List_it1 : Map_it1.second)
         PyList_Append(temp3, PyFloat_FromDouble(List_it1));
-      cout << PyList_Size(temp3) << endl;
       PyDict_SetDefault(FuncVecDict,
                         PyUnicode_FromString((Map_it1.first).c_str()), Py_None);
       PyDict_SetItemString(FuncVecDict, Map_it1.first.c_str(), temp3);
@@ -378,7 +363,7 @@ PyMethodDef IR2Vec_core_Methods[] = {
 };
 struct PyModuleDef IR2Vec_def = {
     PyModuleDef_HEAD_INIT,
-    "IR2Vec_pkg.core", /* name of module NOT THE NAME OF PACKAGE*/
+    "IR2Vec.core", /* name of module NOT THE NAME OF PACKAGE*/
     "take .bc/.ll as input and generates corresponding IR2VEc "
     "Embeddings", /* module documentation, may be NULL */
     -1,           /* size of per-interpreter state of the module,
diff --git a/Manylinux2014_Compliant_Source/pkg/IR2Vec/preparation.py b/Manylinux2014_Compliant_Source/pkg/IR2Vec/preparation.py
new file mode 100755
index 00000000..b443a7be
--- /dev/null
+++ b/Manylinux2014_Compliant_Source/pkg/IR2Vec/preparation.py
@@ -0,0 +1,4 @@
+import pathlib as pl
+
+install_loc = pl.Path(__file__).parent.resolve()
+install_loc_pkg = str(install_loc)
diff --git a/Manylinux2014_Compliant_Source/pkg/IR2Vec_pkg/preparation.py b/Manylinux2014_Compliant_Source/pkg/IR2Vec_pkg/preparation.py
deleted file mode 100755
index 46547a9d..00000000
--- a/Manylinux2014_Compliant_Source/pkg/IR2Vec_pkg/preparation.py
+++ /dev/null
@@ -1,17 +0,0 @@
-import subprocess as sp
-import os
-import sys
-import pathlib as pl
-
-install_loc = pl.Path(__file__).parent.resolve()
-install_loc_pkg = str(install_loc)
-so_files = os.scandir(install_loc_pkg)
-core_so = ""
-for x in so_files:
-    if x.is_file():
-        if "core.cpython" in x.name:
-            core_so = x.name
-core_so = install_loc_pkg + "/" + core_so
-patch_elf = "patchelf" + " " + "--set-rpath" + " " + install_loc_pkg + " " + core_so
-patch_elf = patch_elf.split(" ")
-sp.check_call(patch_elf)
diff --git a/Manylinux2014_Compliant_Source/pkg/Manifest.in b/Manylinux2014_Compliant_Source/pkg/Manifest.in
index 0b2296d6..ec391c9d 100755
--- a/Manylinux2014_Compliant_Source/pkg/Manifest.in
+++ b/Manylinux2014_Compliant_Source/pkg/Manifest.in
@@ -1,4 +1,1 @@
 include ./seedEmbeddingVocab-300-llvm12.txt
-recursive-include ./IR2Vec_include/*
-recursive-include ./llvm/*
-recursive-include ./llvm-c/*
diff --git a/Manylinux2014_Compliant_Source/pkg/build.sh b/Manylinux2014_Compliant_Source/pkg/build.sh
new file mode 100644
index 00000000..ab9b40bd
--- /dev/null
+++ b/Manylinux2014_Compliant_Source/pkg/build.sh
@@ -0,0 +1,24 @@
+#!/bin/bash
+
+set -eu
+export CXX=clang++
+export CC=clang
+
+rm -rf build || true
+mkdir build
+cd build
+
+curl -sOJ https://gitlab.com/libeigen/eigen/-/archive/3.3.7/eigen-3.3.7.tar.gz
+tar -xzf eigen-3.3.7.tar.gz
+mkdir eigen-build
+cd eigen-build
+cmake ../eigen-3.3.7 && make && make install
+
+cd ..
+cmake -DCMAKE_BUILD_TYPE=Release ../src && make -j"$(nproc)" && make install
+
+cd ..
+cp src/include/utils.h Manylinux2014_Compliant_Source/pkg/IR2Vec/
+cp vocabulary/seedEmbeddingVocab-*.txt Manylinux2014_Compliant_Source/pkg/IR2Vec/
+
+bash Manylinux2014_Compliant_Source/pkg/regen-oracle.sh
diff --git a/Manylinux2014_Compliant_Source/pkg/regen-oracle.sh b/Manylinux2014_Compliant_Source/pkg/regen-oracle.sh
new file mode 100644
index 00000000..17ba69e1
--- /dev/null
+++ b/Manylinux2014_Compliant_Source/pkg/regen-oracle.sh
@@ -0,0 +1,41 @@
+#!/bin/bash
+
+set -eu
+
+cd src/test-suite
+
+rm -rf oracle
+
+SEED_VERSION="llvm12"
+SRC_WD="PE-benchmarks"
+DEST_FOLDER_LL="PE-benchmarks-llfiles-${SEED_VERSION}"
+DEST_FOLDER_SYM="oracle/SYM_${SEED_VERSION}_f"
+DEST_FOLDER_FA="oracle/FA_${SEED_VERSION}_f"
+DEST_FOLDER_SYM_P="oracle/SYM_${SEED_VERSION}"
+DEST_FOLDER_FA_P="oracle/FA_${SEED_VERSION}"
+
+mkdir -p ${DEST_FOLDER_LL}
+
+for d in ${SRC_WD}/*.c ${SRC_WD}/*.cpp ${SRC_WD}/*.cc; do
+	echo "Compiling ${d} to IR"
+	name=$(basename ${d}) && oname=${name%.*} && clang -S -emit-llvm -Xclang -disable-O0-optnone ${d} -o ${DEST_FOLDER_LL}/${oname}.ll &
+done
+wait
+
+mkdir -p ${DEST_FOLDER_SYM}
+mkdir -p ${DEST_FOLDER_FA}
+mkdir -p ${DEST_FOLDER_SYM_P}
+mkdir -p ${DEST_FOLDER_FA_P}
+
+IR2VEC_PATH=../../build/bin/ir2vec
+
+VOCAB_PATH="../../vocabulary/seedEmbeddingVocab-300-${SEED_VERSION}.txt"
+
+while IFS= read -r d; do
+	echo "Generating embeddings for ${d}"
+	${IR2VEC_PATH} -sym -vocab=${VOCAB_PATH} -o ${DEST_FOLDER_SYM}/ir2vec.txt -level f ${d} &>/dev/null
+	${IR2VEC_PATH} -fa -vocab=${VOCAB_PATH} -o ${DEST_FOLDER_FA}/ir2vec.txt -level f ${d} &>/dev/null
+	${IR2VEC_PATH} -sym -vocab=${VOCAB_PATH} -o ${DEST_FOLDER_SYM_P}/ir2vec.txt -level p ${d} >/dev/null
+	${IR2VEC_PATH} -fa -vocab=${VOCAB_PATH} -o ${DEST_FOLDER_FA_P}/ir2vec.txt -level p ${d} >/dev/null
+done <index-${SEED_VERSION}.files
+wait
diff --git a/Manylinux2014_Compliant_Source/pkg/setup.py b/Manylinux2014_Compliant_Source/pkg/setup.py
index 9ecae337..1feead47 100755
--- a/Manylinux2014_Compliant_Source/pkg/setup.py
+++ b/Manylinux2014_Compliant_Source/pkg/setup.py
@@ -1,33 +1,83 @@
 from setuptools import setup, Extension
 
+import subprocess as sp
+import pathlib as pl
+
+import re
+
+version_regex = re.compile(r"^project\(ir2vec VERSION (?P<version>[^)]+)\)$")
+llvm_libs_regex = re.compile(
+    r"^llvm_map_components_to_libnames\(llvm_libs (?P<libs>[^)]+)\)$"
+)
+
+LLVM_LIBS = []
+VERSION = ""
+DESCRIPTION = ""
+
+with (pl.Path(__file__).resolve().parents[2] / "src" / "CMakeLists.txt").open() as f:
+    for line in f:
+        if not VERSION:
+            vmatch = version_regex.match(line)  # Not using walrus because Python3.6
+            if vmatch:
+                VERSION = vmatch.group("version")
+                continue
+        if not LLVM_LIBS:
+            libmatch = llvm_libs_regex.match(line)
+            if libmatch:
+                LLVM_LIBS = libmatch.group("libs").split()
+                continue
+        if VERSION and LLVM_LIBS:
+            break
+
+with (pl.Path(__file__).parent / "IR2Vec" / "README.md").open() as f:
+    DESCRIPTION = f.read()
+
+
+def get_llvm_files():
+    out = sp.run(
+        ["llvm-config", "--link-static", "--libfiles"] + LLVM_LIBS, stdout=sp.PIPE
+    )
+    files = out.stdout.decode("utf8").split()
+    return files
+
+
 IR2Vec_core = Extension(
-    "IR2Vec_pkg.core",
-    sources=["IR2Vec_pkg/core.cpp"],
-    include_dirs=[
-        "./IR2Vec_pkg",
-        "./IR2Vec_pkg/IR2Vec_include",
-    ],  # list of directories to search for C/C++ header files (in Unix form for portability)
+    "IR2Vec.core",
+    sources=["IR2Vec/core.cpp"],
+    include_dirs=["./IR2Vec"],
     libraries=["z"],
-    extra_objects=["./libIR2Vec.a", "./libLLVMMother.a"],
+    extra_objects=["/usr/local/lib/libIR2Vec.a"] + get_llvm_files(),
     extra_compile_args=["-v"],
 )
 
 setup(
-    name="IR2Vec_pkg",
+    name="IR2Vec",
     author="Shikhar Jain",
     author_email="cs22mtech02002@iith.ac.in",
-    version="1.0.0",
+    version=VERSION,
     description="given input .ll/.bc generates corresponding IR2Vec embeddings in a file or on stdout",
-    ext_modules=[IR2Vec_core],  # A list of Python extensions to be built
-    packages=["IR2Vec_pkg"],  # A list of Python packages that distutils will manipulate
-    # package_data={'':['*.so*','./IR2Vec_include/*','./llvm/*','./llvm-c/*','seedEmbeddingVocab-300-llvm12.txt']},
-    package_data={
-        "": [
-            "./IR2Vec_include/*",
-            "./llvm/*",
-            "./llvm-c/*",
-            "seedEmbeddingVocab-300-llvm12.txt",
-        ]
-    },
+    long_description=DESCRIPTION,
+    long_description_content_type="text/markdown",
+    url="https://github.com/IITH-Compilers/IR2Vec",
+    license="BSD 4-Clause",
+    classifiers=[
+        "Development Status :: 5 - Production/Stable",
+        "Intended Audience :: Developers",
+        "Intended Audience :: Science/Research",
+        "License :: OSI Approved :: BSD License",
+        "Programming Language :: C++",
+        "Programming Language :: Python :: 3",
+        "Programming Language :: Python :: 3.6",
+        "Programming Language :: Python :: 3.7",
+        "Programming Language :: Python :: 3.8",
+        "Programming Language :: Python :: 3.9",
+        "Programming Language :: Python :: 3.10",
+        "Programming Language :: Python :: 3.11",
+        "Topic :: Scientific/Engineering :: Artificial Intelligence",
+        "Topic :: Software Development :: Compilers",
+    ],
+    ext_modules=[IR2Vec_core],
+    packages=["IR2Vec"],
+    package_data={"": ["seedEmbeddingVocab-*.txt"]},
     include_package_data=True,
 )
diff --git a/src/include/utils.h b/src/include/utils.h
index f3745628..5e6b744b 100644
--- a/src/include/utils.h
+++ b/src/include/utils.h
@@ -49,7 +49,7 @@ std::unique_ptr<llvm::Module> getLLVMIR();
 void collectDataFromVocab(std::map<std::string, Vector> &opcMap);
 void scaleVector(Vector &vec, float factor);
 // newly added
-auto getDemagledName(llvm::Function *function);
+std::string getDemagledName(const llvm::Function *function);
 char *getActualName(llvm::Function *function);
 std::string updatedRes(IR2Vec::Vector tmp, llvm::Function *f, llvm::Module *M);
 } // namespace IR2Vec
diff --git a/src/utils.cpp b/src/utils.cpp
index e5bf1050..d959ff88 100644
--- a/src/utils.cpp
+++ b/src/utils.cpp
@@ -7,6 +7,7 @@
 #include "utils.h"
 #include "IR2Vec.h"
 #include <fstream>
+#include <string>
 
 using namespace llvm;
 using namespace IR2Vec;
@@ -69,13 +70,15 @@ void IR2Vec::scaleVector(Vector &vec, float factor) {
 }
 
 // Function to get demangled function name
-auto IR2Vec::getDemagledName(llvm::Function *function) {
+std::string IR2Vec::getDemagledName(const llvm::Function *function) {
   auto functionName = function->getName().str();
   std::size_t sz = 17;
   int status;
   char *const readable_name =
       __cxa_demangle(functionName.c_str(), 0, &sz, &status);
-  auto demangledName = status == 0 ? std::string(readable_name) : functionName;
+  auto demangledName =
+      status == 0 ? std::string(readable_name) : std::string(functionName);
+  free(readable_name);
   return demangledName;
 }
 


Test patch:
diff --git a/Manylinux2014_Compliant_Source/pkg/tests/test_ir2vec.py b/Manylinux2014_Compliant_Source/pkg/tests/test_ir2vec.py
new file mode 100644
index 00000000..14b926dc
--- /dev/null
+++ b/Manylinux2014_Compliant_Source/pkg/tests/test_ir2vec.py
@@ -0,0 +1,104 @@
+import pathlib as pl
+import IR2Vec
+import pytest
+
+from collections import defaultdict
+
+ABS_ACCURACY = 1e-4
+
+TEST_SUITE_DIR = pl.Path(__file__).resolve().parents[3] / "src" / "test-suite"
+SEED_VERSION = (
+    list(IR2Vec.preparation.install_loc.glob("seed*.txt"))[0]
+    .name.split(".")[0]
+    .split("-")[-1]
+)
+
+ll_files = []
+path = TEST_SUITE_DIR / f"index-{SEED_VERSION}.files"
+with (TEST_SUITE_DIR / f"index-{SEED_VERSION}.files").open() as f:
+    for ll_file in f:
+        ll_files.append(ll_file)
+
+
+def read_f_file(path):
+    f_map = defaultdict(dict)
+    with path.open() as f:
+        for line in f:
+            fouts = line.split("=")
+            vec = fouts[-1]
+            fname = "=".join(fouts[:-1])
+            fname = fname.strip()
+            path, only_fname = fname.split(".cpp", 1)
+            filename = "".join([path.split("/")[1], ".ll"])
+            only_fname = only_fname.strip()[2:]
+            vec = list(map(float, vec.strip().split()))
+            f_map[filename][only_fname] = vec
+    return f_map
+
+
+def read_p_file(path):
+    p_vectors = []
+    with path.open() as f:
+        for line in f:
+            p_vectors.append(list(map(float, line.strip().split())))
+    return p_vectors
+
+
+def test_fa_p():
+    p_vectors = []
+    for file in ll_files:
+        full_path = str((TEST_SUITE_DIR / file).resolve()).strip()
+        output = IR2Vec.generateEmbeddings(full_path, "fa", "p")
+        p_vectors.append(output["Program_List"])
+    p_vectors_oracle = read_p_file(
+        TEST_SUITE_DIR / "oracle" / f"FA_{SEED_VERSION}" / "ir2vec.txt"
+    )
+    for idx, v in enumerate(p_vectors):
+        assert v == pytest.approx(p_vectors_oracle[idx], abs=ABS_ACCURACY)
+
+
+def test_sym_p():
+    p_vectors = []
+    for file in ll_files:
+        full_path = str((TEST_SUITE_DIR / file).resolve()).strip()
+        output = IR2Vec.generateEmbeddings(full_path, "sym", "p")
+        p_vectors.append(output["Program_List"])
+    p_vectors_oracle = read_p_file(
+        TEST_SUITE_DIR / "oracle" / f"SYM_{SEED_VERSION}" / "ir2vec.txt"
+    )
+    for idx, v in enumerate(p_vectors):
+        assert v == pytest.approx(p_vectors_oracle[idx], abs=ABS_ACCURACY)
+
+
+def test_fa_f():
+    f_vecs = defaultdict(dict)
+    for file in ll_files:
+        full_path = (TEST_SUITE_DIR / file).resolve()
+        output = IR2Vec.generateEmbeddings(str(full_path).strip(), "fa", "f")
+        for fun, vec in output["Function_Dict"].items():
+            f_vecs[full_path.name.strip()][fun.strip()] = vec
+    f_vecs_oracle = read_f_file(
+        TEST_SUITE_DIR / "oracle" / f"FA_{SEED_VERSION}_f" / "ir2vec.txt"
+    )
+    for pname, funs in f_vecs_oracle.items():
+        for fname, vec in funs.items():
+            assert vec == pytest.approx(
+                f_vecs[pname][fname], abs=ABS_ACCURACY
+            ), f"Checking {pname}: {fname}"
+
+
+def test_sym_f():
+    f_vecs = defaultdict(dict)
+    for file in ll_files:
+        full_path = (TEST_SUITE_DIR / file).resolve()
+        output = IR2Vec.generateEmbeddings(str(full_path).strip(), "sym", "f")
+        for fun, vec in output["Function_Dict"].items():
+            f_vecs[full_path.name.strip()][fun.strip()] = vec
+    f_vecs_oracle = read_f_file(
+        TEST_SUITE_DIR / "oracle" / f"SYM_{SEED_VERSION}_f" / "ir2vec.txt"
+    )
+    for pname, funs in f_vecs_oracle.items():
+        for fname, vec in funs.items():
+            assert vec == pytest.approx(
+                f_vecs[pname][fname], abs=ABS_ACCURACY
+            ), f"Checking {pname}: {fname}"